├── .gitignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Example
├── .swiftlint.yml
├── NotTwitter
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── 120@2x.png
│ │ │ ├── 152-1.png
│ │ │ ├── 152.png
│ │ │ ├── 167.png
│ │ │ ├── 180.png
│ │ │ ├── Contents.json
│ │ │ └── peek-square.png
│ │ ├── Contents.json
│ │ ├── compose.imageset
│ │ │ ├── Contents.json
│ │ │ └── compose.png
│ │ ├── profile-large.imageset
│ │ │ ├── Contents.json
│ │ │ └── profile.png
│ │ ├── profile-small.imageset
│ │ │ ├── Contents.json
│ │ │ └── profile-small.png
│ │ ├── promo.imageset
│ │ │ ├── Contents.json
│ │ │ └── promo-no-logo.jpg
│ │ ├── reply.imageset
│ │ │ ├── Contents.json
│ │ │ └── reply.png
│ │ ├── share.imageset
│ │ │ ├── Contents.json
│ │ │ └── share.png
│ │ └── star.imageset
│ │ │ ├── Contents.json
│ │ │ └── star.png
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Cell.swift
│ ├── ContentView.swift
│ ├── Info.plist
│ ├── SwiftUI
│ │ ├── ProfileBackgroundModifier.swift
│ │ ├── ProfileFollowsView.swift
│ │ ├── ProfileHeaderView.swift
│ │ ├── ProfileOptionsView.swift
│ │ └── ProfileView.swift
│ ├── TextView.swift
│ ├── Theming.swift
│ └── TimelineViewController.swift
├── Peek.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ ├── xcshareddata
│ │ └── xcdebugger
│ │ │ └── Breakpoints_v2.xcbkptlist
│ └── xcuserdata
│ │ ├── Shaps.xcuserdatad
│ │ └── xcdebugger
│ │ │ └── Breakpoints_v2.xcbkptlist
│ │ └── apple.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
├── Peek.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
├── Peek
│ └── Base.lproj
│ │ └── LaunchScreen.storyboard
├── Podfile
├── Podfile.lock
└── Pods
│ ├── Local Podspecs
│ └── Peek.podspec.json
│ ├── Manifest.lock
│ ├── Pods.xcodeproj
│ ├── project.pbxproj
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Peek.xcscheme
│ └── Target Support Files
│ ├── Peek
│ ├── Info.plist
│ ├── Peek-Info.plist
│ ├── Peek-dummy.m
│ ├── Peek-prefix.pch
│ ├── Peek-umbrella.h
│ ├── Peek.modulemap
│ └── Peek.xcconfig
│ └── Pods-NotTwitter
│ ├── Info.plist
│ ├── Pods-NotTwitter-Info.plist
│ ├── Pods-NotTwitter-acknowledgements.markdown
│ ├── Pods-NotTwitter-acknowledgements.plist
│ ├── Pods-NotTwitter-dummy.m
│ ├── Pods-NotTwitter-frameworks.sh
│ ├── Pods-NotTwitter-resources.sh
│ ├── Pods-NotTwitter-umbrella.h
│ ├── Pods-NotTwitter.debug.xcconfig
│ ├── Pods-NotTwitter.modulemap
│ └── Pods-NotTwitter.release.xcconfig
├── LICENSE
├── PaintCode
├── Absolute Layout.pcvd
├── Application.pcvd
├── Attributes.pcvd
├── AutoResize.pcvd
├── Controller.pcvd
├── Device.pcvd
├── Hierarchy.pcvd
├── Layers.pcvd
├── Layout.pcvd
├── Orientation.pcvd
├── RectEdge.pcvd
├── Relative Layout.pcvd
├── Report.pcvd
├── Reports.pcvd
├── Screen.pcvd
├── SingleOrientation.pcvd
├── Toggle Inspectors.pcvd
├── Trash.pcvd
└── View.pcvd
├── Peek.podspec
├── Pod
└── Classes
│ ├── Accessory Views
│ ├── BoolAccessoryView.swift
│ ├── ColorAccessoryView.swift
│ └── PeekAccessoryProviding.swift
│ ├── Controllers & Views
│ ├── Inspectors
│ │ ├── CollapsibleSections.swift
│ │ ├── PeekInspectorCell.swift
│ │ └── PreviewCell.swift
│ ├── Overlays
│ │ ├── Layout
│ │ │ ├── PeekLayoutOverlayView.swift
│ │ │ ├── PeekLayoutView.swift
│ │ │ └── PeekMetricView.swift
│ │ ├── PeekButton.swift
│ │ ├── PeekOverlayView.swift
│ │ ├── PeekSelectionView.swift
│ │ └── Text
│ │ │ ├── LayoutManager.swift
│ │ │ └── PeekTextOverlayView.swift
│ ├── PeekInspectorViewController.swift
│ ├── PeekPresentationController.swift
│ ├── PeekSectionedViewController.swift
│ ├── PeekViewController.swift
│ ├── Reporting
│ │ ├── Report.swift
│ │ ├── ReportActivity.swift
│ │ └── ReportViewController.swift
│ └── UIViewController+Modal.swift
│ ├── Coordinator
│ ├── Attribute.swift
│ ├── Coordinator.swift
│ └── Group.swift
│ ├── GraphicsRenderer
│ ├── ImageRenderer.swift
│ ├── PDFRenderer.swift
│ ├── Platforms.swift
│ ├── Renderer.swift
│ └── RendererDrawable.swift
│ ├── Helpers
│ ├── Bool+Toggle.swift
│ ├── CGSize+Resize.swift
│ ├── Collection+NilOrEmpty.swift
│ ├── Color+Extensions.swift
│ ├── Color.swift
│ ├── Constraints.swift
│ ├── Enum+Cases.swift
│ ├── Enum+Descriptions.swift
│ ├── NSNumber+Extensions.swift
│ ├── NSObject+Extensions.swift
│ ├── PeekTapGestureRecognizer.swift
│ ├── String+Extensions.swift
│ ├── UIDevice+Extensions.swift
│ ├── UIImage+Resize.swift
│ ├── UIView+Extensions.swift
│ ├── UIViewController+Extensions.swift
│ └── UIWindow+Extensions.swift
│ ├── Images
│ ├── Images+Inspectors.swift
│ ├── Images+Orientation.swift
│ └── Images+OrientationMask.swift
│ ├── Model
│ ├── ContextDataSource.swift
│ ├── Peekable.swift
│ └── UIView+Filter.swift
│ ├── Peek.swift
│ ├── PeekOptions.swift
│ ├── PeekTheme+Colors.swift
│ ├── Peekable
│ ├── Bundle+Peekable.swift
│ ├── CALayer+Peekable.swift
│ ├── NSAttributedString+Peekable.swift
│ ├── NSLayoutConstraint+Peekable.swift
│ ├── NSString+Peekable.swift
│ ├── UIActivityIndicatorView+Peekable.swift
│ ├── UIApplication+Peekable.swift
│ ├── UIBarButtonItem+Peekable.swift
│ ├── UIButton+Peekable.swift
│ ├── UIColor+Peekable.swift
│ ├── UIControl+Peekable.swift
│ ├── UIDevice+Peekable.swift
│ ├── UIFont+Peekable.swift
│ ├── UIImage+Peekable.swift
│ ├── UIImageView+Peekable.swift
│ ├── UILabel+Peekable.swift
│ ├── UINavigationBar+Peekable.swift
│ ├── UIPageControl+Peekable.swift
│ ├── UIPicker+Peekable.swift
│ ├── UIProgressView+Peekable.swift
│ ├── UIScreen+Peekable.swift
│ ├── UIScrollView+Peekable.swift
│ ├── UISegmentedControl+Peekable.swift
│ ├── UISlider+Peekable.swift
│ ├── UIStackView+Peekable.swift
│ ├── UIStepper+Peekable.swift
│ ├── UISwitch+Peekable.swift
│ ├── UITextField+Peekable.swift
│ ├── UITextView+Peekable.swift
│ ├── UIToolbar+Peekable.swift
│ ├── UIView+Peekable.swift
│ └── UIViewController+Peekable.swift
│ ├── Transformers
│ ├── NSNumber+Transformer.swift
│ ├── NSValue+Transformer.swift
│ └── UIColor+Transformer.swift
│ └── VolumeController.swift
├── README.md
├── preview.gif
├── preview.jpg
└── pull_request_template.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS X
2 | .DS_Store
3 |
4 | # Xcode
5 | build/
6 | *.pbxuser
7 | !default.pbxuser
8 | *.mode1v3
9 | !default.mode1v3
10 | *.mode2v3
11 | !default.mode2v3
12 | *.perspectivev3
13 | !default.perspectivev3
14 | xcuserdata/
15 | *.xccheckout
16 | profile
17 | *.moved-aside
18 | DerivedData
19 | *.hmap
20 | *.ipa
21 |
22 | # Bundler
23 | .bundle
24 |
25 | # Carthage
26 | Carthage
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | 5.2.0
4 |
5 | - Swift 4.1 support
6 | - Objective-C support returns
7 | - Minor refactoring/cleanup
8 | -
9 |
10 | 5.1.0
11 |
12 | Note: This will be the last release targetting Swift 4.0
13 |
14 | **[Added]**
15 |
16 | Peek now supports a Light theme
17 | Peek now recommends alternate values for enum types
18 | Peek now provides a Static Library variant via Cocoapods: `pod 'PeekStatic'`
19 | Peek now supports Carthage
20 |
21 | **[Removed]**
22 |
23 | Classes and functions that should never have been public have been removed
24 |
25 | **[Fixed]**
26 |
27 | Fixing branch name in CONTRIBUTING.md and pull_request_template.md
28 | Lots of small refactors and optimizations thanks to @valeriyvan
29 |
30 | 5.0 (Major Release)
31 | -
32 |
33 | - All new design
34 | - Unified Inspectors:
35 | - Collapse/Expand Groups
36 | - Nested Inspectors
37 | - Previews
38 | - Revamped Reporting
39 | - Accessibilty, StackViews & More
40 | - Removed InkKit & SwiftLayout dependencies
41 | - and more
42 |
43 | > Note: Dropped support for iOS 8.x.
44 |
45 | 4.0
46 | -
47 |
48 | Just a Swift compatibility update.
49 | Minor changes as per Swift APIs but no functional changes to Peek.
50 |
51 | 3.0
52 | -
53 |
54 | Swift 3.x unfortunately broke some of the compatilibity issues I required to work with the runtime.
55 | Please use the Swift 4 version instead.
56 |
57 | 2.2.0
58 | -
59 |
60 | * Slack integration
61 | * Email reports
62 | * Screenshot upload block (for Slack)
63 | * NSAttributedString support, including paragraph styles
64 |
65 | 2.1.0
66 | -
67 |
68 | * Enable with options
69 | * Force shake gesture on device
70 | * Allow container selection
71 |
72 | 2.0 (Major Release)
73 | -
74 |
75 | * Absolute layout overlay
76 | * Multiple inspectors
77 | * Swift Support
78 | * iOS 8.3 Support
79 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at shapsuk@me.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # There are a few guidelines to follow when contributing to this project.
2 |
3 | 1. Always use a Pull Request to submit a change
4 | 2. If its a non-trivial change or new feature, always discuss it with the core contributor(s) first via the issues – PRs that don't follow this rule will likely be declined
5 | 3. No new dependencies will be accepted
6 | 4. Extensions support
7 | 5. Always use SwiftLint to ensure coding styles are met
8 | 6. Make sure you pull all recent changes from `develop` and fix any conflicts
9 |
10 | ## Pull Requests
11 |
12 | Pull requests should also point to `develop`. No requests made to `master` will be allowed.
13 |
14 | All changes, no matter how trivial, must be done via pull request. Commits should never be made directly on the master branch.
15 |
16 | ## Feature Requests
17 |
18 | If you have a feature request, please open an Issue about it first. I will reply to all feature requests but its important that it fits within the design goals and feature roadmap of the product.
19 |
20 | So open an issue and we can discuss it, I'm always open to new ideas and suggestions, I just prefer to discuss first.
21 |
22 | ## Dependencies
23 |
24 | One of Peek's design goals is to keep things simple and to have extremely minimal impact on the running app. To that end, I have slowly implemented light-weight versions of libraries that were previously included and managed to strip out all other dependencies.
25 |
26 | > Thus, no new dependencies will be introduced into Peek in the future.
27 |
28 | ## Extensions
29 |
30 | However there are times where a 3rd party component adds value to the project. To satisfy this requirement I am currently working on an Extension based architecture that will make this easier to build where the dependency is inverted. Those projects can depend on Peek instead and still benefit from the best of both worlds
31 |
32 | ## SwiftLint
33 |
34 | The project has already been configured to use SwiftLint, so ensure you have this installed and all issues fixed before submitting a PR
35 |
36 | ## README
37 |
38 | Where applicable, you should ensure the README is also maintained. A typical example is where a new feature is introduced that warrants some explanation, or perhaps an update to the changelog.
39 |
--------------------------------------------------------------------------------
/Example/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | excluded:
2 | - Pods
3 |
4 | included:
5 | - ../Pod
6 |
7 | disabled_rules:
8 | - class_delegate_protocol
9 | - redundant_string_enum_value
10 | - type_name
11 | - redundant_optional_initialization
12 | - operator_whitespace
13 | - trailing_whitespace
14 | - line_length
15 | - todo
16 | - nesting
17 | - cyclomatic_complexity
18 | - function_body_length
19 | - identifier_name
20 | - trailing_comma
21 |
22 | file_length:
23 | warning: 500
24 | error: 700
25 |
26 | large_tuple:
27 | warning: 10
28 |
29 | force_cast:
30 | warning
31 |
32 | force_try:
33 | warning
34 |
35 | function_parameter_count:
36 | warning: 6
37 |
--------------------------------------------------------------------------------
/Example/NotTwitter/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // NotTwitter
4 | //
5 | // Created by Shaps Benkau on 10/03/2018.
6 | // Copyright © 2018 Snippex. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Peek
11 |
12 | @UIApplicationMain
13 | final class AppDelegate: UIResponder, UIApplicationDelegate {
14 |
15 | var window: UIWindow?
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
18 | Theme.apply()
19 |
20 | window?.peek.enableWithOptions { options in
21 | options.theme = .dark
22 | options.activationMode = .auto
23 | options.ignoresContainerViews = false
24 |
25 | /*
26 | Configure the metadata asscociated with this app.
27 | */
28 | options.metadata = [
29 | "Environment": "UAT"
30 | ]
31 | }
32 |
33 | return true
34 | }
35 |
36 | override func motionBegan(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
37 | // iOS 8/9 requires device motion handlers to be on the AppDelegate
38 | window?.peek.handleShake(motion)
39 | }
40 |
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/AppIcon.appiconset/120@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/Example/NotTwitter/Assets.xcassets/AppIcon.appiconset/120@2x.png
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/AppIcon.appiconset/152-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/Example/NotTwitter/Assets.xcassets/AppIcon.appiconset/152-1.png
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/AppIcon.appiconset/152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/Example/NotTwitter/Assets.xcassets/AppIcon.appiconset/152.png
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/AppIcon.appiconset/167.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/Example/NotTwitter/Assets.xcassets/AppIcon.appiconset/167.png
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/AppIcon.appiconset/180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/Example/NotTwitter/Assets.xcassets/AppIcon.appiconset/180.png
--------------------------------------------------------------------------------
/Example/NotTwitter/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 | "size" : "60x60",
35 | "idiom" : "iphone",
36 | "filename" : "120@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "60x60",
41 | "idiom" : "iphone",
42 | "filename" : "180.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "idiom" : "ipad",
47 | "size" : "20x20",
48 | "scale" : "1x"
49 | },
50 | {
51 | "idiom" : "ipad",
52 | "size" : "20x20",
53 | "scale" : "2x"
54 | },
55 | {
56 | "idiom" : "ipad",
57 | "size" : "29x29",
58 | "scale" : "1x"
59 | },
60 | {
61 | "idiom" : "ipad",
62 | "size" : "29x29",
63 | "scale" : "2x"
64 | },
65 | {
66 | "idiom" : "ipad",
67 | "size" : "40x40",
68 | "scale" : "1x"
69 | },
70 | {
71 | "idiom" : "ipad",
72 | "size" : "40x40",
73 | "scale" : "2x"
74 | },
75 | {
76 | "size" : "76x76",
77 | "idiom" : "ipad",
78 | "filename" : "152-1.png",
79 | "scale" : "1x"
80 | },
81 | {
82 | "size" : "76x76",
83 | "idiom" : "ipad",
84 | "filename" : "152.png",
85 | "scale" : "2x"
86 | },
87 | {
88 | "size" : "83.5x83.5",
89 | "idiom" : "ipad",
90 | "filename" : "167.png",
91 | "scale" : "2x"
92 | },
93 | {
94 | "size" : "1024x1024",
95 | "idiom" : "ios-marketing",
96 | "filename" : "peek-square.png",
97 | "scale" : "1x"
98 | }
99 | ],
100 | "info" : {
101 | "version" : 1,
102 | "author" : "xcode"
103 | },
104 | "properties" : {
105 | "pre-rendered" : true
106 | }
107 | }
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/AppIcon.appiconset/peek-square.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/Example/NotTwitter/Assets.xcassets/AppIcon.appiconset/peek-square.png
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/compose.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "universal",
13 | "filename" : "compose.png",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/compose.imageset/compose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/Example/NotTwitter/Assets.xcassets/compose.imageset/compose.png
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/profile-large.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "universal",
13 | "filename" : "profile.png",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/profile-large.imageset/profile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/Example/NotTwitter/Assets.xcassets/profile-large.imageset/profile.png
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/profile-small.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "universal",
13 | "filename" : "profile-small.png",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | },
21 | "properties" : {
22 | "template-rendering-intent" : "original"
23 | }
24 | }
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/profile-small.imageset/profile-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/Example/NotTwitter/Assets.xcassets/profile-small.imageset/profile-small.png
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/promo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "universal",
13 | "filename" : "promo-no-logo.jpg",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | },
21 | "properties" : {
22 | "template-rendering-intent" : "original"
23 | }
24 | }
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/promo.imageset/promo-no-logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/Example/NotTwitter/Assets.xcassets/promo.imageset/promo-no-logo.jpg
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/reply.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "universal",
13 | "filename" : "reply.png",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/reply.imageset/reply.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/Example/NotTwitter/Assets.xcassets/reply.imageset/reply.png
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/share.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "universal",
13 | "filename" : "share.png",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/share.imageset/share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/Example/NotTwitter/Assets.xcassets/share.imageset/share.png
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/star.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "universal",
13 | "filename" : "star.png",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/NotTwitter/Assets.xcassets/star.imageset/star.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/Example/NotTwitter/Assets.xcassets/star.imageset/star.png
--------------------------------------------------------------------------------
/Example/NotTwitter/Cell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Cell.swift
3 | // NotTwitter
4 | //
5 | // Created by Shaps Benkau on 10/03/2018.
6 | // Copyright © 2018 Snippex. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public final class Cell: UITableViewCell {
12 |
13 | @IBOutlet weak var profileImageView: UIImageView!
14 | @IBOutlet weak var usernameLabel: UILabel!
15 | @IBOutlet weak var messageLabel: TextView!
16 | @IBOutlet weak var embedImageView: UIImageView!
17 | @IBOutlet weak var replyButton: UIButton!
18 | @IBOutlet weak var favouriteButton: UIButton!
19 | @IBOutlet weak var shareButton: UIButton!
20 |
21 | public override func awakeFromNib() {
22 | super.awakeFromNib()
23 |
24 | replyButton.titleLabel?.font = UIFont.preferredFont(forTextStyle: .footnote)
25 | favouriteButton.titleLabel?.font = UIFont.preferredFont(forTextStyle: .footnote)
26 | shareButton.titleLabel?.font = UIFont.preferredFont(forTextStyle: .footnote)
27 |
28 | if #available(iOS 10.0, *) {
29 | usernameLabel.adjustsFontForContentSizeCategory = true
30 | messageLabel.adjustsFontForContentSizeCategory = true
31 | replyButton.titleLabel?.adjustsFontForContentSizeCategory = true
32 | favouriteButton.titleLabel?.adjustsFontForContentSizeCategory = true
33 | shareButton.titleLabel?.adjustsFontForContentSizeCategory = true
34 | }
35 |
36 | if #available(iOS 11.0, *) {
37 | replyButton.adjustsImageSizeForAccessibilityContentSizeCategory = true
38 | favouriteButton.adjustsImageSizeForAccessibilityContentSizeCategory = true
39 | shareButton.adjustsImageSizeForAccessibilityContentSizeCategory = true
40 | }
41 |
42 | selectedBackgroundView = UIView()
43 | selectedBackgroundView?.backgroundColor = .selection
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/Example/NotTwitter/ContentView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | @available(iOS 13.0, *)
4 | struct ContentView: View {
5 | @State var a: String = "AAAAA"
6 | @State var b: String = "BBBB"
7 | @State var c: String = "CCCCCC"
8 |
9 | var body: some View {
10 | VStack {
11 | ZStack(alignment: .mid) {
12 | // create vertical and horizontal
13 | // space to align to
14 | HStack { Spacer() }
15 | VStack { Spacer() }
16 |
17 | VStack(alignment: .midX) {
18 | Text(self.a)
19 |
20 | HStack(alignment: .center) {
21 | Text(self.c)
22 |
23 |
24 | Text(self.b)
25 | .font(.title)
26 | .border(Color.blue)
27 | .alignmentGuide(.midX) { d in
28 | (d[.leading] + d[.trailing])/2
29 | }
30 | .alignmentGuide(.midY) { d in
31 | (d[.top] + d[.bottom])/2
32 | }
33 | }
34 | }
35 | }
36 | .layoutPriority(1.0)
37 |
38 | TextField("", text: self.$b).textFieldStyle(RoundedBorderTextFieldStyle())
39 | }
40 | }
41 | }
42 |
43 | @available(iOS 13.0, *)
44 | fileprivate extension HorizontalAlignment {
45 | @available(iOS 13.0, *)
46 | enum MidX : AlignmentID {
47 | static func defaultValue(in d: ViewDimensions) -> CGFloat {
48 | return (d[.leading] + d[.trailing])/2
49 | }
50 | }
51 |
52 | static let midX = HorizontalAlignment(MidX.self)
53 | }
54 |
55 | @available(iOS 13.0, *)
56 | fileprivate extension VerticalAlignment {
57 | @available(iOS 13.0, *)
58 | enum MidY : AlignmentID {
59 | static func defaultValue(in d: ViewDimensions) -> CGFloat {
60 | return (d[.top] + d[.bottom])/2
61 | }
62 | }
63 |
64 | static let midY = VerticalAlignment(MidY.self)
65 | }
66 |
67 | @available(iOS 13.0, *)
68 | fileprivate extension Alignment {
69 | @available(iOS 13.0, *)
70 | static let mid = Alignment(horizontal: .midX, vertical: .midY)
71 | }
72 |
73 | @available(iOS 13.0, *)
74 | struct ContentView_Previews: PreviewProvider {
75 | static var previews: some View {
76 | ContentView()
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/Example/NotTwitter/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Not Twitter
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 | $(MARKETING_VERSION)
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 |
--------------------------------------------------------------------------------
/Example/NotTwitter/SwiftUI/ProfileBackgroundModifier.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | @available(iOS 13, *)
4 | struct ProfileBackgroundModifier: ViewModifier {
5 | func body(content: Content) -> some View {
6 | content
7 | .background(
8 | RoundedRectangle(cornerRadius: 10, style: .continuous)
9 | .foregroundColor(Color(.systemGray5))
10 | )
11 | }
12 | }
13 |
14 | @available(iOS 13, *)
15 | struct ProfileBackgroundModifier_Previews: PreviewProvider {
16 | static var previews: some View {
17 | HStack {
18 | Spacer()
19 | /*@START_MENU_TOKEN@*/Text("Hello, World!")/*@END_MENU_TOKEN@*/
20 | Spacer()
21 | }
22 | .modifier(ProfileBackgroundModifier())
23 | .previewLayout(.sizeThatFits)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Example/NotTwitter/SwiftUI/ProfileFollowsView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | @available(iOS 13, *)
4 | struct TweetFollowersView: View {
5 |
6 | var body: some View {
7 | VStack {
8 | HStack {
9 | Spacer()
10 | VStack {
11 | Text("FOLLOWERS")
12 | .font(.callout)
13 | .foregroundColor(.secondary)
14 | Text("4,559")
15 | .font(.title)
16 | }
17 |
18 | Spacer()
19 | Divider()
20 | Spacer()
21 |
22 | VStack {
23 | Text("FOLLOWING")
24 | .font(.callout)
25 | .foregroundColor(.secondary)
26 | Text("256")
27 | .font(.title)
28 | }
29 |
30 | Spacer()
31 | }
32 | }
33 | .padding(.vertical)
34 | }
35 |
36 | }
37 |
38 | @available(iOS 13, *)
39 | struct ProfileFollowsView_Previews: PreviewProvider {
40 | static var previews: some View {
41 | TweetFollowersView()
42 | .fixedSize(horizontal: false, vertical: true)
43 | .previewLayout(.sizeThatFits)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Example/NotTwitter/SwiftUI/ProfileHeaderView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | @available(iOS 13, *)
4 | struct ProfileHeaderView: View {
5 |
6 | var body: some View {
7 | ZStack(alignment: .bottomLeading) {
8 | HStack {
9 | Image("promo")
10 | .resizable()
11 | .scaledToFit()
12 | .aspectRatio(1, contentMode: .fill)
13 | }
14 |
15 | HStack {
16 | Image("profile-large")
17 | .overlay(
18 | Circle()
19 | .stroke(lineWidth: 2)
20 | .foregroundColor(Color(.systemGroupedBackground))
21 | )
22 |
23 | VStack(alignment: .leading, spacing: 5) {
24 | Text("Shaps Benkau")
25 | .font(.headline)
26 |
27 | Text("@shaps")
28 | .foregroundColor(.secondary)
29 | }
30 | .alignmentGuide(VerticalAlignment.center) {
31 | d in d[.top] - 10
32 | }
33 | }
34 | .alignmentGuide(.bottom) {
35 | d in d[VerticalAlignment.center]
36 | }
37 | .padding(.horizontal)
38 | }
39 | .clipped()
40 | }
41 |
42 | }
43 |
44 | @available(iOS 13, *)
45 | struct ProfileHeaderView_Previews: PreviewProvider {
46 | static var previews: some View {
47 | ProfileHeaderView()
48 | .previewLayout(.fixed(width: 320, height: 300))
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Example/NotTwitter/SwiftUI/ProfileOptionsView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | @available(iOS 13, *)
4 | struct ProfileOptionsView: View {
5 |
6 | var body: some View {
7 | VStack(spacing: 0) {
8 | HStack {
9 | Text("Tweets")
10 | Spacer()
11 | Image(systemName: "chevron.right")
12 | .foregroundColor(.secondary)
13 | }
14 | .padding()
15 |
16 | Divider()
17 | .padding(.leading)
18 |
19 | HStack(spacing: 20) {
20 | Text("Lists")
21 | Spacer()
22 | Image(systemName: "chevron.right")
23 | .foregroundColor(.secondary)
24 | }
25 | .padding()
26 | }
27 | }
28 |
29 | }
30 |
31 | @available(iOS 13, *)
32 | struct ProfileOptionsView_Previews: PreviewProvider {
33 | static var previews: some View {
34 | ProfileOptionsView()
35 | .previewLayout(.sizeThatFits)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Example/NotTwitter/SwiftUI/ProfileView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | @available(iOS 13, *)
4 | struct ProfileView: View {
5 |
6 | var body: some View {
7 | ScrollView {
8 | ProfileHeaderView()
9 |
10 | VStack(spacing: 20) {
11 | TweetFollowersView()
12 | .modifier(ProfileBackgroundModifier())
13 |
14 | ProfileOptionsView()
15 | .modifier(ProfileBackgroundModifier())
16 | }
17 | .padding()
18 | }
19 | .background(
20 | Color(.systemGroupedBackground)
21 | .edgesIgnoringSafeArea(.all)
22 | )
23 | .navigationBarTitle("Shaps", displayMode: .inline)
24 | }
25 |
26 | }
27 |
28 | @available(iOS 13, *)
29 | struct ProfileView_Previews: PreviewProvider {
30 | static var previews: some View {
31 | ProfileView()
32 | .edgesIgnoringSafeArea(.top)
33 | .preferredColorScheme(.dark)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Example/NotTwitter/TextView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TextView.swift
3 | // NotTwitter
4 | //
5 | // Created by Shaps Benkau on 10/03/2018.
6 | // Copyright © 2018 Snippex. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public final class TextView: UITextView {
12 |
13 | public override func awakeFromNib() {
14 | super.awakeFromNib()
15 |
16 | textContainerInset = .zero
17 | textContainer.lineFragmentPadding = 0
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/Example/NotTwitter/Theming.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Theming.swift
3 | // NotTwitter
4 | //
5 | // Created by Shaps Benkau on 10/03/2018.
6 | // Copyright © 2018 Snippex. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIColor {
12 |
13 | public static var separator: UIColor {
14 | return UIColor(red: 189/255, green: 198/255, blue: 205/255, alpha: 1)
15 | }
16 |
17 | public static var background: UIColor {
18 | return .white
19 | }
20 |
21 | public static var selection: UIColor {
22 | return UIColor(red: 0.9, green: 0.9, blue: 0.9, alpha: 1)
23 | }
24 |
25 | }
26 |
27 | public struct Theme {
28 |
29 | public static func apply() {
30 | let bar = UINavigationBar.appearance()
31 |
32 | bar.barTintColor = .background
33 | bar.titleTextAttributes = [
34 | .foregroundColor: UIColor(red: 21/255, green: 23/255, blue: 26/255, alpha: 1),
35 | .font: UIFont.systemFont(ofSize: 16, weight: .black)
36 | ]
37 |
38 | let table = UITableView.appearance()
39 |
40 | table.backgroundColor = .background
41 | table.separatorColor = .separator
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/Example/NotTwitter/TimelineViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TimelineViewController.swift
3 | // NotTwitter
4 | //
5 | // Created by Shaps Benkau on 10/03/2018.
6 | // Copyright © 2018 Snippex. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SwiftUI
11 | import Peek
12 |
13 | public final class TimelineViewController: UITableViewController {
14 |
15 | public override func viewDidLoad() {
16 | super.viewDidLoad()
17 |
18 | navigationItem.rightBarButtonItem?.accessibilityHint = "New Message"
19 | navigationItem.rightBarButtonItem?.accessibilityIdentifier = "navigation.newMessage"
20 | }
21 |
22 | public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
23 | return 5
24 | }
25 |
26 | public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
27 | let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! Cell
28 | return cell
29 | }
30 |
31 | public override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
32 | tableView.deselectRow(at: indexPath, animated: true)
33 |
34 | if #available(iOS 13, *) {
35 | let controller = HostingController(rootView: ProfileView())
36 | navigationController?.pushViewController(controller, animated: true)
37 | }
38 | }
39 |
40 | }
41 |
42 | extension TimelineViewController {
43 |
44 | @IBAction private func newMessage() { print("New message") }
45 | @IBAction private func toggleFavourite() { print("Favourite toggled") }
46 | @IBAction private func reshare() { print("Re-shared") }
47 |
48 | }
49 |
50 | // MARK: Peek
51 | extension TimelineViewController {
52 |
53 | public override var canBecomeFirstResponder: Bool {
54 | return true
55 | }
56 |
57 | public override func motionBegan(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
58 | // iOS 10 now requires device motion handlers to be on a UIViewController
59 | view.window?.peek.handleShake(motion)
60 | }
61 |
62 | }
63 |
64 | @available(iOS 13, *)
65 | final class HostingController: UIHostingController where Content: View {
66 |
67 | public override var canBecomeFirstResponder: Bool {
68 | return true
69 | }
70 |
71 | public override func motionBegan(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
72 | // iOS 10 now requires device motion handlers to be on a UIViewController
73 | view.window?.peek.handleShake(motion)
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/Example/Peek.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/Peek.xcodeproj/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/Example/Peek.xcodeproj/xcuserdata/Shaps.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/Example/Peek.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Peek-Example.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 607FACCF1AFB9204008FA782
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Example/Peek.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Example/Peek.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/Peek.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/Peek.xcworkspace/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/Example/Podfile:
--------------------------------------------------------------------------------
1 | source 'https://github.com/CocoaPods/Specs.git'
2 | use_frameworks!
3 |
4 | target 'NotTwitter' do
5 | platform :ios, '9.0'
6 | pod 'Peek', :path => '../', :configurations => ['Debug']
7 | end
8 |
--------------------------------------------------------------------------------
/Example/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Peek (5.3.0)
3 |
4 | DEPENDENCIES:
5 | - Peek (from `../`)
6 |
7 | EXTERNAL SOURCES:
8 | Peek:
9 | :path: "../"
10 |
11 | SPEC CHECKSUMS:
12 | Peek: 4209f7aa72d00244616f6b4804739c04cae2e457
13 |
14 | PODFILE CHECKSUM: c29c492fe40889a0ba9734d1c078df79ffe7b766
15 |
16 | COCOAPODS: 1.8.4
17 |
--------------------------------------------------------------------------------
/Example/Pods/Local Podspecs/Peek.podspec.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Peek",
3 | "version": "5.3.0",
4 | "swift_versions": [
5 | "5.1"
6 | ],
7 | "summary": "All new design. Inspect your iOS application at runtime.",
8 | "homepage": "https://152percent.com/peek",
9 | "screenshots": "https://images.squarespace-cdn.com/content/v1/58d1c3c1b3db2b27db51464f/1521730411276-S3UCD05HTDG34PWBGM4N/ke17ZwdGBToddI8pDm48kEWP3-hvREnweJ050wvhyvB7gQa3H78H3Y0txjaiv_0fDoOvxcdMmMKkDsyUqMSsMWxHk725yiiHCCLfrh8O1z5QPOohDIaIeljMHgDF5CVlOqpeNLcJ80NK65_fV7S1UdrULnJwJtUwRUNy9fIMUJZw9x8WqpJ4rfPF_qYxQ1vxK19DM50qGfsFZg32uC5Iyw/Peek+Promo+%E2%80%93+No+Logo.jpg?format=2500w",
10 | "license": "MIT",
11 | "authors": {
12 | "Shaps Benkau": "shapsuk@me.com"
13 | },
14 | "source": {
15 | "git": "https://github.com/shaps80/Peek.git",
16 | "tag": "5.3.0"
17 | },
18 | "social_media_url": "https://twitter.com/shaps",
19 | "platforms": {
20 | "ios": "9.0"
21 | },
22 | "requires_arc": true,
23 | "source_files": "Pod/Classes/**/*.{swift,h,m}",
24 | "swift_version": "5.1"
25 | }
26 |
--------------------------------------------------------------------------------
/Example/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Peek (5.3.0)
3 |
4 | DEPENDENCIES:
5 | - Peek (from `../`)
6 |
7 | EXTERNAL SOURCES:
8 | Peek:
9 | :path: "../"
10 |
11 | SPEC CHECKSUMS:
12 | Peek: 4209f7aa72d00244616f6b4804739c04cae2e457
13 |
14 | PODFILE CHECKSUM: c29c492fe40889a0ba9734d1c078df79ffe7b766
15 |
16 | COCOAPODS: 1.8.4
17 |
--------------------------------------------------------------------------------
/Example/Pods/Pods.xcodeproj/xcshareddata/xcschemes/Peek.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
52 |
53 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Peek/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 5.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Peek/Peek-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 5.3.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Peek/Peek-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Peek : NSObject
3 | @end
4 | @implementation PodsDummy_Peek
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Peek/Peek-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Peek/Peek-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double PeekVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char PeekVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Peek/Peek.modulemap:
--------------------------------------------------------------------------------
1 | framework module Peek {
2 | umbrella header "Peek-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Peek/Peek.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Peek
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
4 | PODS_BUILD_DIR = ${BUILD_DIR}
5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
6 | PODS_ROOT = ${SRCROOT}
7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
9 | SKIP_INSTALL = YES
10 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
11 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-NotTwitter/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-NotTwitter/Pods-NotTwitter-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-NotTwitter/Pods-NotTwitter-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## Peek
5 |
6 | Copyright (c) 2016 Shaps Benkau
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | Generated by CocoaPods - https://cocoapods.org
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-NotTwitter/Pods-NotTwitter-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | Copyright (c) 2016 Shaps Benkau <shapsuk@me.com>
18 |
19 | Permission is hereby granted, free of charge, to any person obtaining a copy
20 | of this software and associated documentation files (the "Software"), to deal
21 | in the Software without restriction, including without limitation the rights
22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 | copies of the Software, and to permit persons to whom the Software is
24 | furnished to do so, subject to the following conditions:
25 |
26 | The above copyright notice and this permission notice shall be included in
27 | all copies or substantial portions of the Software.
28 |
29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 | THE SOFTWARE.
36 |
37 | License
38 | MIT
39 | Title
40 | Peek
41 | Type
42 | PSGroupSpecifier
43 |
44 |
45 | FooterText
46 | Generated by CocoaPods - https://cocoapods.org
47 | Title
48 |
49 | Type
50 | PSGroupSpecifier
51 |
52 |
53 | StringsTable
54 | Acknowledgements
55 | Title
56 | Acknowledgements
57 |
58 |
59 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-NotTwitter/Pods-NotTwitter-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_NotTwitter : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_NotTwitter
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-NotTwitter/Pods-NotTwitter-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_NotTwitterVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_NotTwitterVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-NotTwitter/Pods-NotTwitter.debug.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Peek"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Peek/Peek.framework/Headers"
5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
6 | OTHER_LDFLAGS = $(inherited) -framework "Peek"
7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
8 | PODS_BUILD_DIR = ${BUILD_DIR}
9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
13 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-NotTwitter/Pods-NotTwitter.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_NotTwitter {
2 | umbrella header "Pods-NotTwitter-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-NotTwitter/Pods-NotTwitter.release.xcconfig:
--------------------------------------------------------------------------------
1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
2 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
3 | PODS_BUILD_DIR = ${BUILD_DIR}
4 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
5 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
6 | PODS_ROOT = ${SRCROOT}/Pods
7 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016 Shaps Benkau
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/PaintCode/Absolute Layout.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/Absolute Layout.pcvd
--------------------------------------------------------------------------------
/PaintCode/Application.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/Application.pcvd
--------------------------------------------------------------------------------
/PaintCode/Attributes.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/Attributes.pcvd
--------------------------------------------------------------------------------
/PaintCode/AutoResize.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/AutoResize.pcvd
--------------------------------------------------------------------------------
/PaintCode/Controller.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/Controller.pcvd
--------------------------------------------------------------------------------
/PaintCode/Device.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/Device.pcvd
--------------------------------------------------------------------------------
/PaintCode/Hierarchy.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/Hierarchy.pcvd
--------------------------------------------------------------------------------
/PaintCode/Layers.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/Layers.pcvd
--------------------------------------------------------------------------------
/PaintCode/Layout.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/Layout.pcvd
--------------------------------------------------------------------------------
/PaintCode/Orientation.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/Orientation.pcvd
--------------------------------------------------------------------------------
/PaintCode/RectEdge.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/RectEdge.pcvd
--------------------------------------------------------------------------------
/PaintCode/Relative Layout.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/Relative Layout.pcvd
--------------------------------------------------------------------------------
/PaintCode/Report.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/Report.pcvd
--------------------------------------------------------------------------------
/PaintCode/Reports.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/Reports.pcvd
--------------------------------------------------------------------------------
/PaintCode/Screen.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/Screen.pcvd
--------------------------------------------------------------------------------
/PaintCode/SingleOrientation.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/SingleOrientation.pcvd
--------------------------------------------------------------------------------
/PaintCode/Toggle Inspectors.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/Toggle Inspectors.pcvd
--------------------------------------------------------------------------------
/PaintCode/Trash.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/Trash.pcvd
--------------------------------------------------------------------------------
/PaintCode/View.pcvd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/PaintCode/View.pcvd
--------------------------------------------------------------------------------
/Peek.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "Peek"
3 | s.version = "5.3.0"
4 | s.swift_versions = ['5.1']
5 | s.summary = "All new design. Inspect your iOS application at runtime."
6 | s.homepage = "https://152percent.com/peek"
7 | s.screenshots = "https://images.squarespace-cdn.com/content/v1/58d1c3c1b3db2b27db51464f/1521730411276-S3UCD05HTDG34PWBGM4N/ke17ZwdGBToddI8pDm48kEWP3-hvREnweJ050wvhyvB7gQa3H78H3Y0txjaiv_0fDoOvxcdMmMKkDsyUqMSsMWxHk725yiiHCCLfrh8O1z5QPOohDIaIeljMHgDF5CVlOqpeNLcJ80NK65_fV7S1UdrULnJwJtUwRUNy9fIMUJZw9x8WqpJ4rfPF_qYxQ1vxK19DM50qGfsFZg32uC5Iyw/Peek+Promo+%E2%80%93+No+Logo.jpg?format=2500w"
8 | s.license = 'MIT'
9 | s.author = { "Shaps Benkau" => "shapsuk@me.com" }
10 | s.source = { :git => "https://github.com/shaps80/Peek.git", :tag => s.version.to_s }
11 | s.social_media_url = 'https://twitter.com/shaps'
12 | s.platform = :ios, '9.0'
13 | s.requires_arc = true
14 | s.source_files = 'Pod/Classes/**/*.{swift,h,m}'
15 | end
16 |
--------------------------------------------------------------------------------
/Pod/Classes/Accessory Views/BoolAccessoryView.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | /// This accessory view is used in Peek to show a 'switch' representing the underlying Bool value
26 | final class BoolAccessoryView: UIView, PeekAccessoryProviding {
27 |
28 | internal var theme: PeekTheme
29 | fileprivate let size = CGSize(width: 30, height: 20)
30 | fileprivate let value: Bool
31 |
32 | init(value: Bool, theme: PeekTheme = .dark) {
33 | self.theme = theme
34 | self.value = value
35 |
36 | super.init(frame: CGRect(x: 0, y: 0, width: size.width, height: size.height))
37 |
38 | self.backgroundColor = UIColor.clear
39 |
40 | if #available(iOS 11.0, *) {
41 | self.accessibilityIgnoresInvertColors = true
42 | }
43 | }
44 |
45 | required init?(coder aDecoder: NSCoder) {
46 | fatalError("init(coder:) has not been implemented")
47 | }
48 |
49 | override func draw(_ rect: CGRect) {
50 | super.draw(rect)
51 |
52 | let rect = rect.insetBy(dx: 1, dy: 1)
53 |
54 | var bgColor: UIColor?
55 | let bgPath = UIBezierPath(roundedRect: rect, cornerRadius: rect.height / 2)
56 |
57 | var fgColor: UIColor?
58 | var fgPath: UIBezierPath
59 |
60 | if value {
61 | bgColor = UIColor(white: 1, alpha: 0.2)
62 | fgColor = theme.tintColor
63 | fgPath = UIBezierPath(ovalIn: CGRect(x: rect.maxX - rect.height, y: rect.minY, width: rect.height, height: rect.height))
64 | } else {
65 | bgColor = UIColor(white: 1, alpha: 0.2)
66 | fgColor = theme.secondaryTextColor
67 | fgPath = UIBezierPath(ovalIn: CGRect(x: rect.minX, y: rect.minY, width: rect.height, height: rect.height))
68 | }
69 |
70 | bgColor?.setFill()
71 | bgPath.fill()
72 |
73 | fgColor?.setFill()
74 | fgPath.fill()
75 | }
76 |
77 | override var intrinsicContentSize: CGSize {
78 | return CGSize(width: size.width, height: size.height)
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/Pod/Classes/Accessory Views/ColorAccessoryView.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | /// This accessory view is used in Peek to show an icon representing the underlying UIColor value
26 | final class ColorAccessoryView: UIView, PeekAccessoryProviding {
27 |
28 | public var theme: PeekTheme = .dark
29 | fileprivate let color: UIColor?
30 | fileprivate let size = CGSize(width: 20, height: 20)
31 | private let margin: CGFloat = 8
32 |
33 | init(color: UIColor?) {
34 | self.color = color
35 | super.init(frame: CGRect(x: 0, y: 0, width: size.width + margin, height: size.height))
36 | backgroundColor = .clear
37 |
38 | if #available(iOS 11.0, *) {
39 | self.accessibilityIgnoresInvertColors = true
40 | }
41 | }
42 |
43 | required init?(coder aDecoder: NSCoder) {
44 | fatalError("init(coder:) has not been implemented")
45 | }
46 |
47 | override func draw(_ rect: CGRect) {
48 | super.draw(rect)
49 |
50 | let rect = CGRect(x: 8, y: 0, width: size.width, height: size.height).insetBy(dx: 1, dy: 1)
51 | let path = UIBezierPath(roundedRect: rect, cornerRadius: size.height / 2)
52 |
53 | color?.setFill()
54 |
55 | UIColor(white: 1, alpha: 0.1).setStroke()
56 | path.lineWidth = 1
57 | path.fill()
58 | path.stroke()
59 | }
60 |
61 | override var intrinsicContentSize: CGSize {
62 | return CGSize(width: size.width + margin, height: size.height)
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/Pod/Classes/Accessory Views/PeekAccessoryProviding.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PeekAccessoryProviding.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 28/03/2018.
6 | //
7 |
8 | import Foundation
9 |
10 | public protocol PeekAccessoryProviding {
11 | var theme: PeekTheme { get set }
12 | var intrinsicContentSize: CGSize { get }
13 | }
14 |
--------------------------------------------------------------------------------
/Pod/Classes/Controllers & Views/Inspectors/CollapsibleSections.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Sections.swift
3 | // GraphicsRenderer
4 | //
5 | // Created by Shaps Benkau on 23/02/2018.
6 | //
7 |
8 | import Foundation
9 |
10 | private func radians(fromDegrees degrees: CGFloat) -> CGFloat {
11 | return degrees * CGFloat(Double.pi) / 180
12 | }
13 |
14 | internal struct CollapsibleSection {
15 | internal let group: PeekGroup
16 | internal let items: [CollapsibleItem]
17 |
18 | internal var isExpanded: Bool {
19 | get { return UserDefaults.standard.bool(forKey: group.title) }
20 | set { UserDefaults.standard.set(newValue, forKey: group.title) }
21 | }
22 |
23 | internal init(group: PeekGroup, items: [CollapsibleItem]) {
24 | self.group = group
25 | self.items = items
26 | }
27 | }
28 |
29 | internal struct CollapsibleItem {
30 | internal let title: String
31 | internal let attribute: Attribute
32 | }
33 |
34 | internal protocol CollapsibleSectionHeaderViewDelegate: class {
35 | func sectionHeader(_ view: CollapsibleSectionHeaderView, shouldToggleAt index: Int)
36 | }
37 |
38 | internal final class CollapsibleSectionHeaderView: UITableViewHeaderFooterView {
39 |
40 | internal weak var delegate: CollapsibleSectionHeaderViewDelegate? {
41 | didSet {
42 | imageView.isHidden = delegate == nil
43 | gesture.isEnabled = delegate != nil
44 | }
45 | }
46 |
47 | internal let label: UILabel
48 | private lazy var gesture: UITapGestureRecognizer = {
49 | UITapGestureRecognizer(target: self, action: #selector(handleTap(gesture:)))
50 | }()
51 |
52 | private let imageView: UIImageView
53 |
54 | override init(reuseIdentifier: String?) {
55 | label = UILabel(frame: .zero)
56 | imageView = UIImageView(image: nil) // collapsed/expanded indicator
57 | imageView.isHidden = true
58 |
59 | super.init(reuseIdentifier: reuseIdentifier)
60 |
61 | label.numberOfLines = 0
62 |
63 | contentView.addSubview(imageView, constraints: [
64 | equal(\.centerYAnchor),
65 | equal(\.layoutMarginsGuide.trailingAnchor, \.trailingAnchor),
66 | ])
67 |
68 | contentView.addSubview(label, constraints: [
69 | equal(\.layoutMarginsGuide.leadingAnchor, \.leadingAnchor),
70 | equal(\.topAnchor, constant: -12),
71 | equal(\.bottomAnchor, constant: 12)
72 | ])
73 |
74 | NSLayoutConstraint.activate([
75 | label.trailingAnchor.constraint(equalTo: imageView.leadingAnchor, constant: 16)
76 | ])
77 |
78 | gesture.isEnabled = false
79 | addGestureRecognizer(gesture)
80 | }
81 |
82 | @objc private func handleTap(gesture: UITapGestureRecognizer) {
83 | delegate?.sectionHeader(self, shouldToggleAt: tag)
84 | }
85 |
86 | func setExpanded(_ expanded: Bool, completion: (() -> Void)? = nil) {
87 | UIView.animate(withDuration: 0.25, animations: {
88 | let angle = radians(fromDegrees: -90)
89 | self.imageView.transform = expanded ? .identity : CGAffineTransform(rotationAngle: angle)
90 | }, completion: { _ in
91 | completion?()
92 | })
93 | }
94 |
95 | func prepareHeader(for section: Int, theme: PeekTheme = .dark, delegate: CollapsibleSectionHeaderViewDelegate) {
96 | tag = section
97 | self.delegate = delegate
98 |
99 | let thickness: CGFloat = 1.5
100 | let size = CGSize(width: 13 + thickness, height: 8 + thickness)
101 | imageView.image = Images.disclosure(size: size, thickness: thickness, theme: theme)
102 | imageView.tintColor = theme.tintColor
103 | }
104 |
105 | internal required init?(coder aDecoder: NSCoder) {
106 | fatalError("init(coder:) has not been implemented")
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/Pod/Classes/Controllers & Views/Inspectors/PeekInspectorCell.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Peek © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | /// Defines an inspector's cell used to represent a Peek property
26 | final class PeekInspectorCell: UITableViewCell {
27 |
28 | override var accessoryView: UIView? {
29 | didSet { setNeedsUpdateConstraints() }
30 | }
31 |
32 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
33 | super.init(style: .value1, reuseIdentifier: reuseIdentifier)
34 |
35 | indentationWidth = 17
36 | textLabel?.numberOfLines = 0
37 | detailTextLabel?.numberOfLines = 1
38 |
39 | clipsToBounds = true
40 | contentView.clipsToBounds = true
41 |
42 | let selectedView = UIView()
43 | selectedBackgroundView = selectedView
44 | }
45 |
46 | required init?(coder aDecoder: NSCoder) {
47 | fatalError("init(coder:) has not been implemented")
48 | }
49 |
50 | override func setHighlighted(_ highlighted: Bool, animated: Bool) {
51 | let color = accessoryView?.backgroundColor
52 | super.setHighlighted(highlighted, animated: animated)
53 | accessoryView?.backgroundColor = color
54 | }
55 |
56 | override func setSelected(_ selected: Bool, animated: Bool) {
57 | let color = accessoryView?.backgroundColor
58 | super.setSelected(selected, animated: animated)
59 | accessoryView?.backgroundColor = color
60 | }
61 |
62 | override func prepareForReuse() {
63 | super.prepareForReuse()
64 |
65 | textLabel?.text = nil
66 | detailTextLabel?.text = nil
67 | imageView?.image = nil
68 | accessoryView = nil
69 | accessoryType = .none
70 | editingAccessoryView = nil
71 | editingAccessoryType = .none
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/Pod/Classes/Controllers & Views/Inspectors/PreviewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PreviewCell.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 24/02/2018.
6 | //
7 |
8 | import UIKit
9 |
10 | internal final class PreviewCell: UITableViewCell {
11 |
12 | internal let previewImageView: UIImageView
13 |
14 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
15 | previewImageView = UIImageView()
16 | previewImageView.contentMode = .scaleAspectFit
17 | previewImageView.clipsToBounds = true
18 |
19 | previewImageView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
20 | previewImageView.setContentHuggingPriority(.defaultLow, for: .horizontal)
21 | previewImageView.setContentHuggingPriority(.required, for: .vertical)
22 | previewImageView.setContentCompressionResistancePriority(.required, for: .vertical)
23 |
24 | super.init(style: .value1, reuseIdentifier: reuseIdentifier)
25 |
26 | addSubview(previewImageView, constraints: [
27 | equal(\.layoutMarginsGuide.leadingAnchor, \.leadingAnchor),
28 | equal(\.layoutMarginsGuide.trailingAnchor, \.trailingAnchor),
29 | equal(\.topAnchor, constant: -16),
30 | equal(\.bottomAnchor, constant: 16)
31 | ])
32 |
33 | clipsToBounds = true
34 | contentView.clipsToBounds = true
35 | }
36 |
37 | required init?(coder aDecoder: NSCoder) {
38 | fatalError("init(coder:) has not been implemented")
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/Pod/Classes/Controllers & Views/Overlays/Layout/PeekLayoutOverlayView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PeekLayoutView.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 12/03/2018.
6 | //
7 |
8 | import UIKit
9 |
10 | internal final class PeekLayoutOverlayView: PeekOverlayView {
11 |
12 | private lazy var layoutView: PeekLayoutView = {
13 | let view = PeekLayoutView(overlayView: self, borderColor: UIColor(white: 1, alpha: 0.5), borderWidth: 1, dashed: true, theme: theme)
14 | view.layer.zPosition = 0
15 | addSubview(view)
16 | return view
17 | }()
18 |
19 | override init(theme: PeekTheme = .dark) {
20 | super.init(theme: theme)
21 | // TODO: Needs to be true once its implemented
22 | allowsMultipleSelection = false
23 | }
24 |
25 | internal required init?(coder aDecoder: NSCoder) {
26 | fatalError("init(coder:) has not been implemented")
27 | }
28 |
29 | override func refresh() {
30 | super.refresh()
31 | layoutView.setNeedsDisplay()
32 | }
33 |
34 | override func updateHighlights(animated: Bool) {
35 | super.updateHighlights(animated: animated)
36 |
37 | guard indexesForSelectedItems.count > 1,
38 | let first = indexesForSelectedItems.first,
39 | let second = indexesForSelectedItems.last else {
40 | return
41 | }
42 |
43 | let primary = viewModels[first]
44 | let secondary = viewModels[second]
45 |
46 | layoutView.frame = primary.frameInPeek(self).union(secondary.frameInPeek(self))
47 | layoutView.primaryView = primary as? UIView
48 | layoutView.secondaryView = secondary as? UIView
49 | layoutView.primarySelectionView = primarySelectionView
50 | layoutView.secondarySelectionView = secondarySelectionView
51 |
52 | if animated {
53 | UIView.animate(withDuration: 0.2, delay: 0, usingSpringWithDamping: 0.9, initialSpringVelocity: 1.1, options: .beginFromCurrentState, animations: {
54 | self.layoutView.refresh()
55 | }, completion: nil)
56 | } else {
57 | layoutView.refresh()
58 | }
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/Pod/Classes/Controllers & Views/Overlays/Layout/PeekMetricView.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | internal struct Metrics {
26 |
27 | var top: CGFloat
28 | var left: CGFloat
29 | var bottom: CGFloat
30 | var right: CGFloat
31 |
32 | init(top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat) {
33 | self.top = top
34 | self.left = left
35 | self.bottom = bottom
36 | self.right = right
37 | }
38 |
39 | }
40 |
41 | internal final class PeekMetricView: UIVisualEffectView {
42 |
43 | static let formatter: NumberFormatter = {
44 | let formatter = NumberFormatter()
45 | formatter.maximumFractionDigits = 1
46 | formatter.minimumFractionDigits = 0
47 | formatter.roundingIncrement = 0.5
48 | return formatter
49 | }()
50 |
51 | fileprivate let label: UILabel
52 |
53 | required init?(coder aDecoder: NSCoder) {
54 | fatalError()
55 | }
56 |
57 | init(theme: PeekTheme = .dark) {
58 | label = UILabel(frame: .zero)
59 | label.font = UIFont.systemFont(ofSize: 11, weight: .semibold)
60 | label.textColor = theme.primaryTextColor
61 | label.textAlignment = .center
62 |
63 | label.setContentCompressionResistancePriority(.required, for: .horizontal)
64 | label.setContentCompressionResistancePriority(.required, for: .vertical)
65 |
66 | label.setContentHuggingPriority(.required, for: .horizontal)
67 | label.setContentHuggingPriority(.required, for: .vertical)
68 |
69 | super.init(effect: UIBlurEffect(style: .extraLight))
70 |
71 | layer.cornerRadius = 3
72 | layer.masksToBounds = true
73 | layer.zPosition = 100
74 |
75 | contentView.addSubview(label, constraints: [
76 | equal(\.leadingAnchor, constant: -2), equal(\.trailingAnchor, constant: 2),
77 | equal(\.topAnchor, constant: -1), equal(\.bottomAnchor, constant: 1)
78 | ])
79 | }
80 |
81 | internal func apply(value: CGFloat) {
82 | label.text = PeekMetricView.formatter.string(from: NSNumber(value: Float(value)))
83 | label.sizeToFit()
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/Pod/Classes/Controllers & Views/Overlays/PeekButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PeekButton.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 07/03/2018.
6 | //
7 |
8 | import UIKit
9 |
10 | internal final class PeekButton: UIControl {
11 |
12 | private var feedbackGenerator: Any?
13 |
14 | @available(iOS 10.0, *)
15 | private func haptic() -> UIImpactFeedbackGenerator? {
16 | return feedbackGenerator as? UIImpactFeedbackGenerator
17 | }
18 |
19 | private lazy var tapGesture: UITapGestureRecognizer = {
20 | return UITapGestureRecognizer(target: self, action: #selector(handleTap(gesture:)))
21 | }()
22 |
23 | private lazy var vibrancyView: UIVisualEffectView = {
24 | return UIVisualEffectView(effect: UIBlurEffect(style: .dark))
25 | }()
26 |
27 | private lazy var visualEffectView: UIVisualEffectView = {
28 | let blur = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
29 | blur.contentView.addSubview(vibrancyView, constraints: [
30 | equal(\.leadingAnchor), equal(\.trailingAnchor),
31 | equal(\.topAnchor), equal(\.bottomAnchor)
32 | ])
33 | return blur
34 | }()
35 |
36 | private lazy var imageView: UIImageView = {
37 | return UIImageView(image: Images.attributes)
38 | }()
39 |
40 | private let theme: PeekTheme
41 |
42 | internal init(theme: PeekTheme) {
43 | self.theme = theme
44 | super.init(frame: .zero)
45 |
46 | if #available(iOS 11.0, *) {
47 | accessibilityIgnoresInvertColors = true
48 | }
49 |
50 | vibrancyView.contentView.addSubview(imageView, constraints: [
51 | equal(\.centerXAnchor), equal(\.centerYAnchor)
52 | ])
53 |
54 | addSubview(visualEffectView, constraints: [
55 | equal(\.leadingAnchor), equal(\.trailingAnchor),
56 | equal(\.topAnchor), equal(\.bottomAnchor)
57 | ])
58 |
59 | addGestureRecognizer(tapGesture)
60 | backgroundColor = .clear
61 | }
62 |
63 | required init?(coder aDecoder: NSCoder) {
64 | fatalError("init(coder:) has not been implemented")
65 | }
66 |
67 | @objc private func handleTap(gesture: UITapGestureRecognizer) {
68 | sendActions(for: .touchUpInside)
69 | }
70 |
71 | override func touchesBegan(_ touches: Set, with event: UIEvent?) {
72 | super.touchesBegan(touches, with: event)
73 | setTransform(CGAffineTransform(scaleX: 1.5, y: 1.5))
74 |
75 | if #available(iOS 10.0, *) {
76 | feedbackGenerator = UIImpactFeedbackGenerator(style: .light)
77 | haptic()?.impactOccurred()
78 | }
79 | }
80 |
81 | override func touchesEnded(_ touches: Set, with event: UIEvent?) {
82 | super.touchesEnded(touches, with: event)
83 | setTransform(.identity)
84 | feedbackGenerator = nil
85 | }
86 |
87 | override func touchesCancelled(_ touches: Set, with event: UIEvent?) {
88 | super.touchesCancelled(touches, with: event)
89 | setTransform(.identity)
90 | feedbackGenerator = nil
91 | }
92 |
93 | private func setTransform(_ transform: CGAffineTransform) {
94 | let damping: CGFloat = transform == .identity ? 1 : 0.45
95 | UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: damping, initialSpringVelocity: 1, options: [.beginFromCurrentState, .allowUserInteraction], animations: {
96 | self.transform = transform
97 | }, completion: nil)
98 | }
99 |
100 | override var intrinsicContentSize: CGSize {
101 | return CGSize(width: 60, height: 60)
102 | }
103 |
104 | override func layoutSubviews() {
105 | super.layoutSubviews()
106 |
107 | let size = bounds.height / 2
108 |
109 | visualEffectView.layer.cornerRadius = size
110 | visualEffectView.layer.masksToBounds = true
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/Pod/Classes/Controllers & Views/Overlays/PeekSelectionView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PeekSelectionView.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 12/03/2018.
6 | //
7 |
8 | import UIKit
9 |
10 | internal class PeekSelectionView: UIView {
11 |
12 | private let borderWidth: CGFloat
13 | private let borderColor: UIColor
14 | private let dashed: Bool
15 |
16 | internal init(borderColor: UIColor?, borderWidth: CGFloat, dashed: Bool = false) {
17 | self.borderColor = borderColor ?? .white
18 | self.borderWidth = borderWidth
19 | self.dashed = dashed
20 |
21 | super.init(frame: .zero)
22 |
23 | backgroundColor = .clear
24 | layer.zPosition = 20
25 |
26 | guard !dashed else { return }
27 |
28 | layer.borderWidth = borderWidth
29 | layer.borderColor = self.borderColor.cgColor
30 | layer.cornerRadius = borderWidth * 2
31 | }
32 |
33 | internal required init?(coder aDecoder: NSCoder) {
34 | fatalError("init(coder:) has not been implemented")
35 | }
36 |
37 | override func draw(_ rect: CGRect) {
38 | super.draw(rect)
39 | guard dashed else { return }
40 |
41 | let inset = borderWidth / 2
42 | let path = UIBezierPath(roundedRect: rect.insetBy(dx: inset, dy: inset), cornerRadius: borderWidth * 2)
43 |
44 | if dashed {
45 | path.setLineDash([4, 4], count: 2, phase: 0)
46 | }
47 |
48 | borderColor.setStroke()
49 | path.stroke()
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/Pod/Classes/Controllers & Views/Overlays/Text/LayoutManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LayoutManager.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 13/03/2018.
6 | //
7 |
8 | import Foundation
9 | import CoreText
10 |
11 | final class LayoutManager: NSLayoutManager {
12 |
13 | override func drawBackground(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint) {
14 | super.drawBackground(forGlyphRange: glyphsToShow, at:origin)
15 |
16 | guard let text = textStorage?.string else { return }
17 |
18 | enumerateLineFragments(forGlyphRange: glyphsToShow)
19 | { (rect: CGRect, usedRect: CGRect, textContainer: NSTextContainer, glyphRange: NSRange, stop: UnsafeMutablePointer) -> Void in
20 |
21 | let characterRange = self.characterRange(forGlyphRange: glyphRange, actualGlyphRange: nil)
22 |
23 | // Draw invisible tab space characters
24 |
25 | let line = (text as NSString).substring(with: characterRange)
26 |
27 | do {
28 | let expr = try NSRegularExpression(pattern: "\t", options: [])
29 |
30 | expr.enumerateMatches(in: line, options: .reportProgress, range: characterRange)
31 | { result, flags, stop in
32 | if let result = result {
33 |
34 | let range = NSMakeRange(result.range.location + characterRange.location, result.range.length)
35 | let characterRect = self.boundingRect(forGlyphRange: range, in: textContainer)
36 |
37 | let symbol = "\u{21E5}"
38 | let attrs = [NSAttributedString.Key.foregroundColor : UIColor.red ]
39 | let height = (symbol as NSString).size(withAttributes: attrs).height
40 | let rect = characterRect.offsetBy(dx: 1, dy: height * 0.5)
41 | symbol.draw(in: rect, withAttributes: attrs)
42 | }
43 |
44 | }
45 |
46 | } catch let error as NSError {
47 | print(error.localizedDescription)
48 | }
49 |
50 | }
51 |
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/Pod/Classes/Controllers & Views/Overlays/Text/PeekTextOverlayView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PeekTextOverlay.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 13/03/2018.
6 | //
7 |
8 | import UIKit
9 |
10 | internal final class PeekTextOverlayView: PeekOverlayView {
11 |
12 | private var textView: UITextView?
13 |
14 | internal init(textView: UITextView) {
15 | self.textView = textView
16 | super.init()
17 | }
18 |
19 | internal required init?(coder aDecoder: NSCoder) {
20 | fatalError("init(coder:) has not been implemented")
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/Pod/Classes/Controllers & Views/Reporting/ReportActivity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReportActivity.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 06/03/2018.
6 | //
7 |
8 | import UIKit
9 | import MobileCoreServices
10 |
11 | internal final class ReportActivity: NSObject, UIActivityItemSource {
12 |
13 | private let report: Report
14 |
15 | internal init(report: Report) {
16 | self.report = report
17 | }
18 |
19 | func activityViewController(_ activityViewController: UIActivityViewController, thumbnailImageForActivityType activityType: UIActivity.ActivityType?, suggestedSize size: CGSize) -> UIImage? {
20 | return report.snapshot?.resized(to: size)
21 | }
22 |
23 | func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
24 | return "Peek Report"
25 | }
26 |
27 | func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
28 | guard let type = activityType else { return report.plainText }
29 |
30 | switch type {
31 | case .mail:
32 | return report.html
33 | default:
34 | return report.plainText
35 | }
36 | }
37 |
38 | func activityViewController(_ activityViewController: UIActivityViewController, subjectForActivityType activityType: UIActivity.ActivityType?) -> String {
39 | let formatter = DateFormatter()
40 | formatter.dateStyle = .short
41 | return "Peek Report: \(formatter.string(from: Date()))"
42 | }
43 |
44 | func activityViewController(_ activityViewController: UIActivityViewController, dataTypeIdentifierForActivityType activityType: UIActivity.ActivityType?) -> String {
45 | guard let type = activityType else { return kUTTypePlainText as String }
46 |
47 | switch type {
48 | case .mail:
49 | return kUTTypeHTML as String
50 | default:
51 | return kUTTypePlainText as String
52 | }
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/Pod/Classes/Controllers & Views/UIViewController+Modal.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+Modal.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 21/02/2018.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIViewController {
11 |
12 | func presentModal(_ viewControllerToPresent: UIViewController, from sourceView: UIView?, animated: Bool, completion: (() -> Void)?) {
13 | let controller = PeekPresentationController(presentedViewController: viewControllerToPresent, presenting: presentingViewController)
14 |
15 | withExtendedLifetime(controller) { _ in
16 | viewControllerToPresent.transitioningDelegate = controller
17 | self.present(viewControllerToPresent, animated: animated, completion: completion)
18 | }
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/Pod/Classes/GraphicsRenderer/Platforms.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 03/10/2016 Snippex Ltd
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | #if os(OSX)
24 | import AppKit
25 | internal typealias Image = NSImage
26 | internal typealias Screen = NSScreen
27 |
28 | extension NSScreen {
29 | internal static var main: NSScreen {
30 | return self.main
31 | }
32 |
33 | internal var scale: CGFloat {
34 | return backingScaleFactor
35 | }
36 | }
37 |
38 | extension NSImage {
39 | internal func pngRepresentation() -> Data? {
40 | return NSBitmapImageRep(data: tiffRepresentation!)?.representation(using: .png, properties: [:])
41 | }
42 |
43 | internal func jpgRepresentation(quality: CGFloat) -> Data? {
44 | return NSBitmapImageRep(data: tiffRepresentation!)?.representation(using: .jpeg, properties: [.compressionFactor: quality])
45 | }
46 | }
47 | #else
48 | import UIKit
49 | internal typealias Image = UIImage
50 | internal typealias Screen = UIScreen
51 |
52 | extension UIImage {
53 | internal func pngRepresentation() -> Data? {
54 | return pngData()
55 | }
56 |
57 | internal func jpgRepresentation(quality: CGFloat) -> Data? {
58 | return jpegData(compressionQuality: quality)
59 | }
60 | }
61 | #endif
62 |
63 | extension CGContext {
64 |
65 | internal static var current: CGContext? {
66 | #if os(OSX)
67 | return NSGraphicsContext.current?.cgContext
68 | #else
69 | return UIGraphicsGetCurrentContext()
70 | #endif
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/Pod/Classes/GraphicsRenderer/Renderer.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 03/10/2016 Snippex Ltd
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import Foundation
24 |
25 | /**
26 | Represents a Renderer error
27 |
28 | - missingContext: The context could not be found or created
29 | */
30 | internal enum RendererError: Error {
31 | case missingContext
32 | case invalidURL
33 | }
34 |
35 | /**
36 | * Defines a renderer format
37 | */
38 | internal protocol RendererFormat: class {
39 |
40 | /**
41 | Returns a default instance, configured for the current device
42 |
43 | - returns: A new renderer format
44 | */
45 | static func `default`() -> Self
46 |
47 | /// Returns the drawable bounds
48 | var bounds: CGRect { get }
49 |
50 | }
51 |
52 |
53 | /**
54 | * Represents a drawable -- used to add drawing support to CGContext, RendererContext and UIGraphicsImageRendererContext
55 | */
56 | internal protocol RendererDrawable {
57 |
58 | var cgContext: CGContext { get }
59 | func fill(_ rect: CGRect)
60 | func fill(_ rect: CGRect, blendMode: CGBlendMode)
61 | func stroke(_ rect: CGRect)
62 | func stroke(_ rect: CGRect, blendMode: CGBlendMode)
63 | func clip(to rect: CGRect)
64 | }
65 |
66 |
67 | /**
68 | * Represents a renderer context, which provides additional drawing methods as well as access to the underlying CGContext
69 | */
70 | internal protocol RendererContext: class, RendererDrawable {
71 | associatedtype Format: RendererFormat
72 | var format: Format { get }
73 | }
74 |
75 | extension CGContext: RendererDrawable {
76 | internal var cgContext: CGContext {
77 | return self
78 | }
79 | }
80 |
81 | #if os(iOS) || os(tvOS)
82 | @available(iOS 10.0, *)
83 | extension UIGraphicsImageRendererContext: RendererDrawable { }
84 | #endif
85 |
86 |
87 | /**
88 | * Represents a renderer
89 | */
90 | internal protocol Renderer: class {
91 |
92 | /// The associated context type this renderer will use
93 | associatedtype Context: RendererContext
94 |
95 | /// Returns the format associated with this renderer
96 | var format: Context.Format { get }
97 |
98 | /// Returns true if this renderer may be used to generate CGImageRefs
99 | var allowsImageOutput: Bool { get }
100 |
101 | init(bounds: CGRect)
102 | }
103 |
104 | extension Renderer {
105 |
106 | /// Default implementation returns false
107 | internal var allowsImageOutput: Bool {
108 | return false
109 | }
110 |
111 | /**
112 | Default implementation returns false
113 | */
114 | internal static func context(with format: RendererFormat) -> CGContext? {
115 | return nil
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/Pod/Classes/GraphicsRenderer/RendererDrawable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 03/10/2016 Snippex Ltd
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import Foundation
24 |
25 | extension RendererDrawable {
26 |
27 | /// Fills the specified rect
28 | ///
29 | /// - Parameter rect: The rect to fill
30 | internal func fill(_ rect: CGRect) {
31 | fill(rect, blendMode: .normal)
32 | }
33 |
34 | /// Fills the specified rect with the given blend mode
35 | ///
36 | /// - Parameters:
37 | /// - rect: The rect to fill
38 | /// - blendMode: The blend mode to apply to this fill
39 | internal func fill(_ rect: CGRect, blendMode: CGBlendMode) {
40 | cgContext.saveGState()
41 | cgContext.setBlendMode(blendMode)
42 | cgContext.fill(rect)
43 | cgContext.restoreGState()
44 | }
45 |
46 | /// Strokes the specified rect
47 | ///
48 | /// - Parameter rect: The rect to stroke
49 | internal func stroke(_ rect: CGRect) {
50 | stroke(rect, blendMode: .normal)
51 | }
52 |
53 | /// Strokes the specified rect with the given blend mode
54 | ///
55 | /// - Parameters:
56 | /// - rect: The rect to stroke
57 | /// - blendMode: The blend more to apply to this stroke
58 | internal func stroke(_ rect: CGRect, blendMode: CGBlendMode) {
59 | cgContext.saveGState()
60 | cgContext.setBlendMode(blendMode)
61 | cgContext.stroke(rect.insetBy(dx: 0.5, dy: 0.5))
62 | cgContext.restoreGState()
63 | }
64 |
65 | /// Clips the context to the specified rect
66 | ///
67 | /// - Parameter rect: The rect to clip to
68 | internal func clip(to rect: CGRect) {
69 | cgContext.saveGState()
70 | cgContext.clip(to: rect)
71 | cgContext.restoreGState()
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Pod/Classes/Helpers/Bool+Toggle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Bool+Toggle.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 04/05/2018.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Bool {
11 |
12 | /// Equivalent to `someBool = !someBool`
13 | ///
14 | /// Useful when operating on long chains:
15 | ///
16 | /// myVar.prop1.prop2.enabled.toggle()
17 | mutating func toggle() {
18 | self = !self
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/Pod/Classes/Helpers/CGSize+Resize.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGRect+Resize.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 20/03/2018.
6 | //
7 |
8 | import CoreGraphics
9 |
10 | internal enum ScaleMode: Int {
11 |
12 | case scaleToFill
13 | case scaleAspectFit
14 | case scaleAspectFill
15 | case center
16 |
17 | }
18 |
19 | extension CGSize {
20 |
21 | /**
22 | Returns a new size, scaled to the specified size using the given scale mode
23 |
24 | - parameter size: The size to scale to
25 | - parameter mode: The scale mode
26 |
27 | - returns: The resulting size
28 | */
29 | internal func scaledTo(size: CGSize, scaleMode mode: ScaleMode) -> CGSize {
30 | var w: CGFloat, h: CGFloat
31 |
32 | switch mode {
33 | case .scaleToFill:
34 | w = size.width
35 | h = size.height
36 | case .scaleAspectFit:
37 | let mW = size.width / self.width
38 | let mH = size.height / self.height
39 |
40 | if mH < mW {
41 | w = mH * self.width
42 | h = size.height
43 | } else {
44 | h = mW * self.height
45 | w = size.width
46 | }
47 | case .scaleAspectFill:
48 | let mW = size.width / self.width
49 | let mH = size.height / self.height
50 |
51 | if mH > mW {
52 | w = mH * self.width
53 | h = size.height
54 | } else {
55 | h = mW * self.height
56 | w = size.width
57 | }
58 | case .center:
59 | w = self.height
60 | h = self.width
61 | }
62 |
63 | return CGSize(width: w, height: h)
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/Pod/Classes/Helpers/Collection+NilOrEmpty.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Collection+NilOrEmpty.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 04/05/2018.
6 | //
7 |
8 | import Foundation
9 |
10 | internal extension Optional where Wrapped: Collection {
11 |
12 | /// Equivalent to `if let value = value, !value.isEmpty`
13 | ///
14 | /// Useful when you need to know whether or not an underlying value exists at all.
15 | ///
16 | /// string.isNilOrEmpty
17 | ///
18 | /// Returns true if `string` is nil or empty. False otherwise
19 | var isNilOrEmpty: Bool {
20 | switch self {
21 | case .some(let wrapped): return wrapped.isEmpty
22 | case .none: return true
23 | }
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/Pod/Classes/Helpers/Color+Extensions.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UIColor {
26 |
27 | internal var hslComponents:(hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat) {
28 | var h: CGFloat = 0, s: CGFloat = 0, l: CGFloat = 0, a: CGFloat = 0
29 | getHue(&h, saturation: &s, brightness: &l, alpha: &a)
30 | return (h, s, l, a)
31 | }
32 |
33 | internal var rgbComponents:(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
34 | var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
35 | getRed(&r, green: &g, blue: &b, alpha: &a)
36 | return (r, g, b, a)
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/Pod/Classes/Helpers/Enum+Cases.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Enum+Cases.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 26/02/2018.
6 | //
7 |
8 | import Foundation
9 |
10 | extension RawRepresentable where RawValue == Int, Self: Hashable {
11 |
12 | private static func cases() -> AnySequence {
13 | return AnySequence { () -> AnyIterator in
14 | var raw = 0
15 | return AnyIterator {
16 | let current: Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: self, capacity: 1) { $0.pointee } }
17 | guard current.hashValue == raw else {
18 | return nil
19 | }
20 | raw += 1
21 | return current
22 | }
23 | }
24 | }
25 |
26 | internal static var all: [Self] {
27 | return Array(self.cases())
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Pod/Classes/Helpers/NSNumber+Extensions.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import Foundation
24 |
25 | extension NSNumber {
26 |
27 | func isBool() -> Bool {
28 | let boolID = CFBooleanGetTypeID()
29 | let numID = CFGetTypeID(self)
30 | return numID == boolID
31 | }
32 |
33 | func isFloat() -> Bool {
34 | switch CFNumberGetType(self) {
35 | case .cgFloatType, .doubleType, .float32Type, .float64Type, .floatType:
36 | return true
37 | default:
38 | return false
39 | }
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/Pod/Classes/Helpers/NSObject+Extensions.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension NSObjectProtocol {
26 |
27 | static func ObjClassName() -> String {
28 | return NSStringFromClass(self).components(separatedBy: ".").last!
29 | }
30 |
31 | func ObjClassName() -> String {
32 | return Self.ObjClassName()
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/Pod/Classes/Helpers/PeekTapGestureRecognizer.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 | import UIKit.UIGestureRecognizerSubclass
25 |
26 | final class PeekTapGestureRecognizer: UITapGestureRecognizer {
27 |
28 | override func touchesBegan(_ touches: Set, with event: UIEvent?) {
29 | super.touchesBegan(touches, with: event!)
30 |
31 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) {
32 | if self.state != .recognized {
33 | self.state = .failed
34 | }
35 | }
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/Pod/Classes/Helpers/String+Extensions.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import Foundation
24 |
25 | extension String {
26 |
27 | // Converts a camel case string to a capitalized one -- e.g. 'firstName' -> 'First Name'
28 | static func capitalized(_ camelCase: String) -> String {
29 | let chars = CharacterSet.uppercaseLetters
30 | var string = camelCase.components(separatedBy: ".").last ?? camelCase
31 | let peekPrefix = "peek_"
32 | let supportPrefix = "supports"
33 |
34 | if string.contains(peekPrefix) {
35 | string = String(string.dropFirst(peekPrefix.count))
36 | }
37 |
38 | if string.contains(supportPrefix) {
39 | string = String(string.dropFirst(supportPrefix.count))
40 | }
41 |
42 | while let range = string.rangeOfCharacter(from: chars) {
43 | let char = string[range]
44 | string.replaceSubrange(range, with: " " + char.lowercased())
45 | }
46 |
47 | return string.capitalized.trimmingCharacters(in: CharacterSet.whitespaces)
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/Pod/Classes/Helpers/UIDevice+Extensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIDevice+Extensions.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 26/03/2018.
6 | //
7 |
8 | import Foundation
9 |
10 | extension UIDevice {
11 |
12 | internal var isSimulator: Bool {
13 | var isSimulator = false
14 | #if (arch(i386) || arch(x86_64))
15 | isSimulator = true
16 | #endif
17 | return isSimulator
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/Pod/Classes/Helpers/UIImage+Resize.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+Resize.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 20/03/2018.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIImage {
11 |
12 | public func resized(to preferredSize: CGSize) -> UIImage {
13 | let newSize = size.scaledTo(size: preferredSize, scaleMode: .scaleAspectFit)
14 | UIGraphicsBeginImageContextWithOptions(newSize, true, UIScreen.main.scale)
15 | let rect = CGRect(origin: .zero, size: newSize)
16 | draw(in: rect)
17 | let image = UIGraphicsGetImageFromCurrentImageContext()
18 | UIGraphicsEndImageContext()
19 | return image ?? self
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/Pod/Classes/Helpers/UIView+Extensions.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UIView {
26 |
27 | /**
28 | Returns the UIViewController that owns this view
29 |
30 | - returns: The owning view controller
31 | */
32 | @objc internal func owningViewController() -> UIViewController? {
33 | var responder: UIResponder? = self
34 |
35 | while !(responder is UIViewController) && superview != nil {
36 | if let next = responder?.next {
37 | responder = next
38 | }
39 | }
40 |
41 | return responder as? UIViewController
42 | }
43 |
44 | /**
45 | Returns the CGRect representing this view, within the coordinates of Peek's overlay view
46 |
47 | - parameter view: The view to translate
48 |
49 | - returns: A CGRect in the coordinate space of Peek's overlay view
50 | */
51 | func frameInPeek(_ view: UIView) -> CGRect {
52 | return convert(bounds, to: view)
53 | }
54 |
55 | /**
56 | Returns the CGRect representing this view, excluding the current CGAffineTransform being applied to it
57 |
58 | - parameter view: The view to translate
59 |
60 | - returns: A CGRect in the coordinator space of Peek's overlay view
61 | */
62 | func frameInPeekWithoutTransform(_ view: UIView) -> CGRect {
63 | let center = self.center
64 | let size = self.bounds.size
65 | let rect = CGRect(x: center.x - size.width / 2, y: center.y - size.height / 2, width: size.width, height: size.height)
66 |
67 | if let superview = self.superview {
68 | return superview.convert(rect, to: view)
69 | }
70 |
71 | return CGRect.zero
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/Pod/Classes/Helpers/UIViewController+Extensions.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UIViewController {
26 |
27 | /**
28 | Returns the top view controller currently on screen in the application
29 |
30 | - returns: The top view controller
31 | */
32 | func topViewController() -> UIViewController {
33 |
34 | if let controller = self as? UINavigationController {
35 | return controller.topViewController?.topViewController() ?? controller
36 | }
37 |
38 | if let controller = self as? UITabBarController {
39 | return controller.selectedViewController?.topViewController() ?? controller
40 | }
41 |
42 | if let controller = presentedViewController {
43 | return controller.topViewController()
44 | }
45 |
46 | return self
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/Pod/Classes/Helpers/UIWindow+Extensions.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | @objc extension UIWindow {
26 |
27 | /// Returns the Peek instance associated with this window
28 | @objc public var peek: Peek {
29 | return objc_getAssociatedObject(self, &PeekAssociationKey.Peek) as? Peek ?? {
30 | let associatedProperty = Peek(window: self)
31 | objc_setAssociatedObject(self, &PeekAssociationKey.Peek, associatedProperty, .OBJC_ASSOCIATION_RETAIN)
32 | return associatedProperty
33 | }()
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/Pod/Classes/Model/ContextDataSource.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import Foundation
24 |
25 | /// Provides a data-source for representing properties in a Context -- used by InspectorViewController
26 | internal final class ContextDataSource {
27 |
28 | internal private(set) var sections: [CollapsibleSection]
29 |
30 | private init(sections: [CollapsibleSection]) {
31 | self.sections = sections
32 | }
33 |
34 | internal init(coordinator: PeekCoordinator) {
35 | sections = Group.all.compactMap { group in
36 | guard let peekGroup = coordinator.groupsMapping[group] else { return nil }
37 |
38 | let items = peekGroup.attributes
39 | .map { CollapsibleItem(title: $0.title, attribute: $0) }
40 |
41 | return CollapsibleSection(group: peekGroup, items: items)
42 | }
43 | }
44 |
45 | internal func filtered(by searchTerm: String?) -> ContextDataSource {
46 | guard let searchText = searchTerm?.trimmingCharacters(in: .whitespaces),
47 | !searchText.isEmpty else {
48 | return self
49 | }
50 |
51 | let sections: [CollapsibleSection] = self.sections.compactMap {
52 | let items = $0.items.filter {
53 | $0.title.localizedCaseInsensitiveContains(searchText)
54 | }
55 |
56 | guard !items.isEmpty else { return nil }
57 | return CollapsibleSection(group: $0.group, items: items)
58 | }
59 |
60 | return ContextDataSource(sections: sections)
61 | }
62 |
63 | internal func attribute(at indexPath: IndexPath) -> Attribute {
64 | return sections[indexPath.section].items[indexPath.item].attribute
65 | }
66 |
67 | internal func setExpanded(_ expanded: Bool, for section: Int) {
68 | sections[section].isExpanded = expanded
69 | }
70 |
71 | internal func toggleVisibility(forSection section: Int) {
72 | sections[section].isExpanded.toggle()
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/Pod/Classes/Model/UIView+Filter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Ignore.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 26/03/2018.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIView {
11 |
12 | /**
13 | Determines if Peek should ignore this view when parsing it into a model
14 |
15 | - parameter peek: The Peek instance
16 |
17 | - returns: Returns true if Peek should ignore this view, false otherwise
18 | */
19 | internal override func isVisibleInOverlay(options: PeekOptions) -> Bool {
20 | let isContainer = isMember(of: UIView.self) && subviews.count > 0
21 | if isContainer && options.ignoresContainerViews { return false }
22 |
23 | let isInvisible = isHidden || alpha == 0 || frame.equalTo(CGRect.zero)
24 | if isInvisible { return false }
25 |
26 | let isTableViewOrCell = isMember(of: UITableViewCell.self) || isMember(of: UITableView.self)
27 | if isTableViewOrCell { return false }
28 |
29 | let isCollectionView = isMember(of: UICollectionView.self)
30 | if isCollectionView { return false }
31 |
32 | let isFullScreen = frame.equalTo(window?.bounds ?? UIScreen.main.bounds)
33 | if isFullScreen { return false }
34 |
35 | if String(describing: classForCoder).hasPrefix("_UIModern") { return true }
36 |
37 | let blacklist = [ "UIPickerTableView", "UIPickerColumnView", "UITableViewCellContentView" ]
38 | let className = String(describing: classForCoder)
39 |
40 | if className.hasPrefix("_") || blacklist.contains(className) {
41 | return false
42 | }
43 |
44 | let invalidContainerClassNames = [ "UINavigationButton" ]
45 | var superview = self.superview
46 |
47 | while superview != nil {
48 | if superview?.isComponent == true {
49 | return false
50 | }
51 |
52 | // also need to check private internal classes
53 | for className in invalidContainerClassNames {
54 | if let klass = NSClassFromString(className) {
55 | if superview?.isMember(of: klass) ?? false {
56 | return false
57 | }
58 | }
59 | }
60 |
61 | superview = superview?.superview
62 | }
63 |
64 | return true
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/Pod/Classes/PeekOptions.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import Foundation
24 |
25 | /**
26 | Available activation modes
27 |
28 | - Auto: Peek will use a shake gesture when running in the Simulator, and the volume controls on a device
29 | - Shake: Peek will use a shake gesture on both the Simulator and a device
30 | */
31 | @objc public enum PeekActivationMode: Int {
32 | /// Peek will use a shake gesture when running in the Simulator, and the volume controls on a device
33 | case auto = 0
34 | /// Peek will use a shake gesture on both the Simulator and a device
35 | case shake
36 | }
37 |
38 | @objc public enum PeekTheme: Int {
39 | case dark = 0
40 | case black
41 | case light
42 | }
43 |
44 | /// Defines various options to use when enabling Peek
45 | public final class PeekOptions: NSObject {
46 |
47 | /// Defines how peek looks (.black mode is optimised for OLED displays). Defaults to .dark
48 | @objc public var theme: PeekTheme = .dark
49 |
50 | /// Defines how Peek is activated/de-activated. Defaults to auto
51 | @objc public var activationMode: PeekActivationMode = .auto
52 |
53 | /// When this is true, views that are not subclassed but contain subviews, will be ignored. Defaults to false
54 | @objc public var ignoresContainerViews = false
55 |
56 | /// You can provide meta data that will be attached to every report. This is useful for passing additional info about the app, e.g. Environment, etc...
57 | @objc public var metadata: [String: String] = [:]
58 |
59 | // MARK: Obsoletions
60 |
61 | @available(*, deprecated, renamed: "ignoresContainerViews")
62 | @objc public var shouldIgnoreContainers: Bool {
63 | get { return ignoresContainerViews }
64 | set { ignoresContainerViews = newValue }
65 | }
66 |
67 | @available(*, deprecated)
68 | @objc public var includeScreenshot = true
69 | @available(*, deprecated, message: "Defaults to UIScreen.main.scale")
70 | @objc public var screenshotScale = UIScreen.main.scale
71 | @available(*, deprecated, message: "Peek now uses the built in UIActivityViewController")
72 | @objc public var slackUserName = "Peek"
73 | @available(*, deprecated, message: "Peek now uses the built in UIActivityViewController")
74 | @objc public var slackRecipient: String?
75 | @available(*, deprecated, message: "Peek now uses the built in UIActivityViewController")
76 | @objc public var slackWebHookURL: URL?
77 | @available(*, deprecated, message: "Peek now uses the built in UIActivityViewController")
78 | @objc public var emailRecipients: [String]?
79 | @available(*, deprecated, message: "Peek now uses the built in UIActivityViewController")
80 | @objc public var emailSubject: String?
81 | @available(*, deprecated, message: "Peek now uses the built in UIActivityViewController")
82 | @objc public var slackImageUploader: ((URLSession, UIImage) -> URL?)?
83 | @available(*, deprecated, renamed: "metadata")
84 | @objc public var reportMetaData: [String: String]?
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/Pod/Classes/PeekTheme+Colors.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PeekTheme+Colors.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 26/03/2018.
6 | //
7 |
8 | import Foundation
9 |
10 | extension PeekTheme {
11 |
12 | internal var overlayBackgroundColor: UIColor? {
13 | return .black
14 | }
15 |
16 | internal var overlayTintColor: UIColor? {
17 | return Color(literalRed: 135, green: 252, blue: 112).system
18 | }
19 |
20 | internal var backgroundColor: UIColor? {
21 | switch self {
22 | case .dark: return Color(hex: "1c1c1c")!.system
23 | case .black: return .black
24 | case .light: return .white
25 | }
26 | }
27 |
28 | internal var selectedBackgroundColor: UIColor? {
29 | switch self {
30 | case .dark: return UIColor(white: 1, alpha: 0.1)
31 | case .black: return UIColor(white: 1, alpha: 0.1)
32 | case .light: return UIColor(white: 0, alpha: 0.1)
33 | }
34 | }
35 |
36 | internal var separatorColor: UIColor? {
37 | switch self {
38 | case .dark: return UIColor(white: 1, alpha: 0.1)
39 | case .black: return UIColor(white: 1, alpha: 0.1)
40 | case .light: return UIColor(white: 0, alpha: 0.1)
41 | }
42 | }
43 |
44 | internal func titleTextColor(isEditing: Bool) -> UIColor? {
45 | switch self {
46 | case .dark: return .white
47 | case .black: return .white
48 | case .light: return isEditing ? .white : .black
49 | }
50 | }
51 |
52 | internal var primaryTextColor: UIColor? {
53 | switch self {
54 | case .dark: return .white
55 | case .black: return .white
56 | case .light: return .black
57 | }
58 | }
59 |
60 | internal var secondaryTextColor: UIColor? {
61 | switch self {
62 | case .dark: return UIColor(white: 1, alpha: 0.6)
63 | case .black: return UIColor(white: 1, alpha: 0.6)
64 | case .light: return Color(hex: "1c1c1c")!.system
65 | }
66 | }
67 |
68 | internal var tintColor: UIColor? {
69 | switch self {
70 | case .dark: return Color(literalRed: 135, green: 252, blue: 112).system
71 | case .black: return Color(literalRed: 135, green: 252, blue: 112).system
72 | case .light: return Color(hex: "4CD863")!.system
73 | }
74 | }
75 |
76 | internal var editingColor: UIColor? {
77 | switch self {
78 | case .dark: return Color(hex: "4CD863")!.system
79 | case .black: return Color(hex: "4CD863")!.system
80 | case .light: return Color(hex: "4CD863")!.system
81 | }
82 | }
83 |
84 | internal var editingCounterColor: UIColor? {
85 | return Color(hex: "3EB454")!.system
86 | }
87 |
88 | internal var disclosureColor: UIColor? {
89 | switch self {
90 | case .dark: return UIColor(white: 1, alpha: 0.6)
91 | case .black: return UIColor(white: 1, alpha: 0.6)
92 | case .light: return UIColor(red: 200/255, green: 200/255, blue: 200/255, alpha: 1)
93 | }
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/Bundle+Peekable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Bundle+Peekable.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 26/02/2018.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Bundle {
11 |
12 | @objc var backgroundModes: [String]? {
13 | return infoDictionary?["UIBackgroundModes"] as? [String]
14 | }
15 |
16 | @objc var capabilities: [String]? {
17 | return infoDictionary?["UIRequiredDeviceCapabilities"] as? [String]
18 | }
19 |
20 | @objc var supportedDevices: String {
21 | let families = infoDictionary?["UIDeviceFamily"] as? [Int]
22 | let iphone = families?.contains(1) ?? false
23 | let ipad = families?.contains(2) ?? false
24 |
25 | if iphone && ipad {
26 | return "Universal"
27 | } else if iphone {
28 | return "iPhone"
29 | } else {
30 | return "iPad"
31 | }
32 | }
33 |
34 | @objc var supportsHealthKit: Bool {
35 | return capabilities?.contains("healthkit") ?? false
36 | }
37 |
38 | @objc var supportsGameKit: Bool {
39 | return capabilities?.contains("gamekit") ?? false
40 | }
41 |
42 | @objc var supportsBackgroundAudio: Bool {
43 | return backgroundModes?.contains("audio") ?? false
44 | }
45 |
46 | @objc var supportsExternalAccessory: Bool {
47 | return backgroundModes?.contains("external-accessory") ?? false
48 | }
49 |
50 | @objc var supportsBackgroundFetch: Bool {
51 | return backgroundModes?.contains("fetch") ?? false
52 | }
53 |
54 | @objc var supportsLocation: Bool {
55 | return backgroundModes?.contains("location") ?? false
56 | }
57 |
58 | @objc var supportsNewsstand: Bool {
59 | return backgroundModes?.contains("newsstand-content") ?? false
60 | }
61 |
62 | @objc var supportsPushNotifications: Bool {
63 | return backgroundModes?.contains("remote-notification") ?? false
64 | }
65 |
66 | @objc var supportsVoip: Bool {
67 | return backgroundModes?.contains("voip") ?? false
68 | }
69 |
70 | @objc var supportsBluetooth: Bool {
71 | return backgroundModes?.contains("bluetooth-central") ?? false
72 | }
73 |
74 | @objc var sharesDataViaBluetooth: Bool {
75 | return backgroundModes?.contains("bluetooth-peripheral") ?? false
76 | }
77 |
78 | @objc var appName: String {
79 | return infoDictionary?["CFBundleName"] as? String ?? "Unknown"
80 | }
81 |
82 | @objc var appIcon: UIImage? {
83 | guard let iconsDictionary = Bundle.main.infoDictionary?["CFBundleIcons"] as? NSDictionary,
84 | let primaryIconsDictionary = iconsDictionary["CFBundlePrimaryIcon"] as? NSDictionary,
85 | let iconFiles = primaryIconsDictionary["CFBundleIconFiles"] as? NSArray,
86 | // First will be smallest for the device class, last will be the largest for device class
87 | let lastIcon = iconFiles.lastObject as? String,
88 | let icon = UIImage(named: lastIcon) else {
89 | return nil
90 | }
91 |
92 | return icon
93 | }
94 |
95 | @objc var version: String {
96 | return infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown"
97 | }
98 |
99 | @objc var build: String {
100 | return infoDictionary?["CFBundleVersion"] as? String ?? "Unknown"
101 | }
102 |
103 | @objc var statusBarAppearance: String {
104 | if infoDictionary?["UIViewControllerBasedStatusBarAppearance"] as? Bool == true {
105 | return "Per Controller"
106 | } else {
107 | return "Application"
108 | }
109 | }
110 |
111 | @objc var supportedOrientations: UIInterfaceOrientationMask {
112 | let application = UIApplication.shared
113 | let window = application.keyWindow
114 | return application.supportedInterfaceOrientations(for: window)
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/CALayer+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension CALayer {
26 |
27 | @objc var peek_borderColor: UIColor? {
28 | if let color = borderColor {
29 | return UIColor(cgColor: color)
30 | }
31 |
32 | return nil
33 | }
34 |
35 | @objc var peek_shadowColor: UIColor? {
36 | if let color = shadowColor {
37 | return UIColor(cgColor: color)
38 | }
39 |
40 | return nil
41 | }
42 |
43 | @objc var peek_backgroundColor: UIColor? {
44 | if let color = backgroundColor {
45 | return UIColor(cgColor: color)
46 | }
47 |
48 | return nil
49 | }
50 |
51 | open override func preparePeek(with coordinator: Coordinator) {
52 | coordinator.appendDynamic(keyPaths: [
53 | "doubleSided",
54 | "allowsGroupOpacity",
55 | "shouldRasterize",
56 | "rasterizationScale",
57 | ], forModel: self, in: .appearance)
58 |
59 | coordinator.appendDynamic(keyPaths: [
60 | "peek_shadowColor",
61 | "shadowOpacity",
62 | "shadowRadius",
63 | "shadowOffset",
64 | ], forModel: self, in: .shadow)
65 |
66 | coordinator.appendDynamic(keyPaths: [
67 | "peek_borderColor",
68 | "borderWidth"
69 | ], forModel: self, in: .border)
70 |
71 | coordinator.appendDynamic(keyPaths: [
72 | "contentsRect",
73 | "contentsCenter",
74 | "contentsScale",
75 | "contentsGravity",
76 | "geometryFlipped",
77 | "anchorPointZ",
78 | "position",
79 | "anchorPoint",
80 | "zPosition",
81 | ], forModel: self, in: .layout)
82 |
83 | var current: AnyClass = classForCoder
84 | coordinator.appendStatic(keyPath: "classForCoder", title: String(describing: current), detail: nil, value: "", in: .classes)
85 |
86 | while let next = current.superclass() {
87 | coordinator.appendStatic(keyPath: "classForCoder", title: String(describing: next), detail: nil, value: "", in: .classes)
88 | current = next
89 | }
90 |
91 | for layer in sublayers ?? [] {
92 | coordinator.appendStatic(keyPath: "layer.classForCoder", title: String(describing: layer.classForCoder), detail: "", value: layer, in: .layers)
93 | }
94 |
95 | super.preparePeek(with: coordinator)
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/NSLayoutConstraint+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension NSLayoutConstraint: PeekDescribing {
26 |
27 | internal var displayName: String {
28 | guard let ascii = perform(Selector(("asciiArtDescription"))) else { return "Unknown" }
29 | var name = "\(ascii)".components(separatedBy: ": ").last
30 |
31 | if name == "nil" {
32 | name = super.description
33 | }
34 |
35 | return name ?? super.description
36 | }
37 |
38 | @objc var peek_firstItem: String {
39 | guard let item = firstItem else { return "nil" }
40 | return "\(item.classForCoder!)"
41 | }
42 |
43 | @objc var peek_secondItem: String {
44 | guard let item = secondItem else { return "nil" }
45 | return "\(item.classForCoder!)"
46 | }
47 |
48 | open override func preparePeek(with coordinator: Coordinator) {
49 | coordinator.appendDynamic(keyPaths: [
50 | "active",
51 | "shouldBeArchived"
52 | ], forModel: self, in: .behaviour)
53 |
54 | (coordinator as? SwiftCoordinator)?
55 | .appendEnum(keyPath: "firstAttribute", into: NSLayoutConstraint.Attribute.self, forModel: self, group: .general)
56 |
57 | coordinator.appendDynamic(keyPaths: ["peek_firstItem"], forModel: self, in: .general)
58 |
59 | (coordinator as? SwiftCoordinator)?
60 | .appendEnum(keyPath: "secondAttribute", into: NSLayoutConstraint.Attribute.self, forModel: self, group: .general)
61 |
62 | coordinator.appendDynamic(keyPaths: ["peek_secondItem"], forModel: self, in: .general)
63 |
64 | (coordinator as? SwiftCoordinator)?
65 | .appendEnum(keyPath: "relation", into: NSLayoutConstraint.Relation.self, forModel: self, group: .general)
66 |
67 | coordinator.appendDynamic(keyPaths: [
68 | "constant", "multiplier", "priority"
69 | ], forModel: self, in: .layout)
70 |
71 | super.preparePeek(with: coordinator)
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/NSString+Peekable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+Peekable.swift
3 | // Peek
4 | //
5 | // Created by Shaps Benkau on 10/03/2018.
6 | //
7 |
8 | import Foundation
9 |
10 | extension NSString {
11 |
12 | internal var peek_preview: UIImage {
13 | let textView = UITextView()
14 |
15 | textView.layoutManager.showsInvisibleCharacters = true
16 | textView.isSelectable = false
17 | textView.isEditable = false
18 | textView.isScrollEnabled = false
19 | textView.textColor = .white
20 | textView.font = UIFont.preferredFont(forTextStyle: .body)
21 | textView.backgroundColor = .clear
22 | textView.text = self as String
23 | textView.frame.size = CGSize(width: 320, height: 150)
24 |
25 | return ImageRenderer(size: textView.bounds.size).image { context in
26 | textView.drawHierarchy(in: context.format.bounds, afterScreenUpdates: true)
27 | }
28 | }
29 |
30 | open override func preparePeek(with coordinator: Coordinator) {
31 | coordinator.appendPreview(image: peek_preview, forModel: self)
32 |
33 | super.preparePeek(with: coordinator)
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/UIActivityIndicatorView+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UIActivityIndicatorView {
26 |
27 | open override func preparePeek(with coordinator: Coordinator) {
28 | coordinator.appendDynamic(keyPaths: ["hidesWhenStopped"], forModel: self, in: .behaviour)
29 | coordinator.appendDynamic(keyPaths: ["isAnimating"], forModel: self, in: .states)
30 | coordinator.appendDynamic(keyPaths: ["color"], forModel: self, in: .appearance)
31 |
32 | (coordinator as? SwiftCoordinator)?
33 | .appendEnum(keyPath: "activityIndicatorViewStyle", into: UIActivityIndicatorView.Style.self, forModel: self, group: .appearance)
34 |
35 | super.preparePeek(with: coordinator)
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/UIApplication+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UIApplication {
26 |
27 | open override func preparePeek(with coordinator: Coordinator) {
28 | if let image = bundle.appIcon {
29 | coordinator.appendPreview(image: image, forModel: self)
30 | }
31 |
32 | coordinator.appendDynamic(keyPaths: [
33 | "bundle.appName",
34 | "bundle.bundleIdentifier",
35 | "bundle.version",
36 | "bundle.build",
37 | "bundle.supportedDevices",
38 | "bundle.statusBarAppearance",
39 | "statusBarFrame",
40 | "applicationIconBadgeNumber"
41 | ], forModel: self, in: .general)
42 |
43 | coordinator.appendDynamic(keyPathToName: [
44 | ["applicationSupportsShakeToEdit": "Supports Shake to Edit"],
45 | ["ignoringInteractionEvents": "Ignoring Interactions"],
46 | ["protectedDataAvailable": "Protected Data Available"]
47 | ], forModel: self, in: .behaviour)
48 |
49 | coordinator.appendDynamic(keyPaths: [
50 | "bundle.supportsBackgroundAudio",
51 | "bundle.supportsExternalAccessory",
52 | "bundle.supportsBackgroundFetch",
53 | "bundle.supportsLocation",
54 | "bundle.supportsNewsstand",
55 | "bundle.supportsPushNotifications",
56 | "bundle.supportsVoip",
57 | "bundle.supportsBluetooth",
58 | "bundle.supportsHealthKit",
59 | "bundle.supportsGameKit",
60 | "bundle.sharesDataViaBluetooth",
61 | ], forModel: self, in: .capabilities)
62 |
63 | super.preparePeek(with: coordinator)
64 | }
65 |
66 | @objc fileprivate var bundle: Bundle {
67 | return Bundle.main
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/UIBarButtonItem+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UIBarButtonItem {
26 |
27 | open override func preparePeek(with coordinator: Coordinator) {
28 | var detail = ""
29 |
30 | if let model = target as? Peekable {
31 | detail = String(describing: model.classForCoder)
32 | }
33 |
34 | var title = ""
35 |
36 | if let action = action {
37 | title = String(describing: action)
38 | }
39 |
40 | coordinator.appendStatic(keyPath: title, title: title, detail: detail, value: target, in: .actions)
41 |
42 | coordinator.appendDynamic(keyPaths: [
43 | "title",
44 | "image",
45 | "landscapeImagePhone"
46 | ], forModel: self, in: .appearance)
47 |
48 | coordinator.appendDynamic(keyPaths: [
49 | "tag"
50 | ], forModel: self, in: .general)
51 |
52 | coordinator.appendDynamic(keyPaths: [
53 | "imageInsets",
54 | "landscapeImagePhoneInsets"
55 | ], forModel: self, in: .layout)
56 |
57 | coordinator.appendDynamic(keyPaths: ["enabled"], forModel: self, in: .behaviour)
58 |
59 | super.preparePeek(with: coordinator)
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/UIColor+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UIColor {
26 |
27 | @objc var peek_alpha: CGFloat {
28 | return CGFloat(Color(system: self)?.rgba.alpha ?? 0)
29 | }
30 |
31 | @objc var peek_HEX: String {
32 | if let hex = Color(system: self)?.toHex(withAlpha: false) {
33 | return "#\(hex)"
34 | } else {
35 | return "Unknown"
36 | }
37 | }
38 |
39 | @objc var peek_HSL: String {
40 | return "\(Int(hslComponents.hue * 360)), \(Int(hslComponents.saturation * 100)), \(Int(hslComponents.brightness * 100))"
41 | }
42 |
43 | @objc var peek_RGB: String {
44 | return "\(Int(rgbComponents.red * 255)), \(Int(rgbComponents.green * 255)), \(Int(rgbComponents.blue * 255))"
45 | }
46 |
47 | @available(iOS 10.0, *)
48 | @objc var colorSpace: String {
49 | let colorSpace = cgColor.colorSpace ?? CGColorSpaceCreateDeviceRGB()
50 | return colorSpace.name as String? ?? "Unknown"
51 | }
52 |
53 | open override func preparePeek(with coordinator: Coordinator) {
54 | if cgColor.pattern != nil || (self != .clear && rgbComponents.alpha != 0) {
55 | let width = UIScreen.main.nativeBounds.width / UIScreen.main.nativeScale
56 | let image = ImageRenderer(size: CGSize(width: width, height: 88)).image { context in
57 | let rect = context.format.bounds
58 | setFill()
59 | UIRectFill(rect)
60 | }
61 |
62 | coordinator.appendPreview(image: image, forModel: self)
63 | }
64 |
65 | if #available(iOS 10.0, *) {
66 | coordinator.appendDynamic(keyPaths: ["colorSpace"], forModel: self, in: .general)
67 | }
68 |
69 | guard cgColor.pattern == nil else {
70 | coordinator.appendStatic(keyPath: "cgColor.pattern", title: "Color", detail: nil, value: "Pattern", in: .general)
71 | return
72 | }
73 |
74 | guard self != .clear else {
75 | coordinator.appendStatic(keyPath: "self", title: "Color", detail: nil, value: "Clear", in: .general)
76 | return
77 | }
78 |
79 | coordinator.appendDynamic(keyPathToName: [
80 | ["peek_HEX": "HEX"],
81 | ["peek_RGB": "RGB"],
82 | ["peek_HSL": "HSL"],
83 | ["peek_alpha": "Alpha"],
84 | ], forModel: self, in: .general)
85 |
86 | super.preparePeek(with: coordinator)
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/UIControl+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UIControl {
26 |
27 | open override func preparePeek(with coordinator: Coordinator) {
28 | coordinator.appendDynamic(keyPaths: [
29 | "enabled", "selected", "highlighted"
30 | ], forModel: self, in: .states)
31 |
32 | (coordinator as? SwiftCoordinator)?
33 | .appendEnum(keyPath: "contentVerticalAlignment", into: UIControl.ContentVerticalAlignment.self, forModel: self, group: .layout)
34 | .appendEnum(keyPath: "contentHorizontalAlignment", into: UIControl.ContentHorizontalAlignment.self, forModel: self, group: .layout)
35 |
36 | super.preparePeek(with: coordinator)
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/UIFont+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UIFont {
26 |
27 | open override func preparePeek(with coordinator: Coordinator) {
28 | coordinator.appendDynamic(keyPaths: [
29 | "familyName",
30 | "fontName",
31 | "pointSize",
32 | ], forModel: self, in: .general)
33 |
34 | coordinator.appendStatic(keyPath: "fontDescriptor", title: "Font Descriptor", detail: fontDescriptor.postscriptName, value: fontDescriptor, in: .general)
35 |
36 | coordinator.appendDynamic(keyPaths: [
37 | "descender",
38 | "capHeight",
39 | "xHeight",
40 | "lineHeight",
41 | "leading"
42 | ], forModel: self, in: .layout)
43 |
44 | super.preparePeek(with: coordinator)
45 | }
46 |
47 | @objc internal var peek_textStyle: String? {
48 | return (fontDescriptor.fontAttributes[.textStyle] as? UIFont.TextStyle)?.rawValue
49 | }
50 |
51 | }
52 |
53 | extension UIFontDescriptor {
54 |
55 | open override func preparePeek(with coordinator: Coordinator) {
56 | if let value = fontAttributes[.textStyle] as? UIFont.TextStyle {
57 | coordinator.appendStatic(keyPath: "textStyle", title: "Text Style", detail: value.rawValue, value: nil, in: .general)
58 | }
59 |
60 | if let value = fontAttributes[.family] as? String {
61 | coordinator.appendStatic(keyPath: "family", title: "Family", detail: value, value: nil, in: .general)
62 | }
63 |
64 | coordinator.appendDynamic(keyPaths: ["postscriptName"], forModel: self, in: .general)
65 |
66 | if let value = fontAttributes[.name] as? String {
67 | coordinator.appendStatic(keyPath: " name", title: "Name", detail: value, value: nil, in: .general)
68 | }
69 |
70 | if let value = fontAttributes[.face] as? String {
71 | coordinator.appendStatic(keyPath: "face", title: "Face", detail: value, value: nil, in: .general)
72 | }
73 |
74 | if let value = fontAttributes[.visibleName] as? String {
75 | coordinator.appendStatic(keyPath: "visibleName", title: "Visible Name", detail: value, value: nil, in: .general)
76 | }
77 |
78 | super.preparePeek(with: coordinator)
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/UIImage+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UIImage {
26 |
27 | open override func preparePeek(with coordinator: Coordinator) {
28 | let preview = renderingMode != .alwaysOriginal ? withRenderingMode(.alwaysTemplate) : self
29 | coordinator.appendPreview(image: preview, forModel: self)
30 |
31 | (coordinator as? SwiftCoordinator)?
32 | .appendEnum(keyPath: "renderingMode", into: UIImage.RenderingMode.self, forModel: self, group: .appearance)
33 | .appendEnum(keyPath: "resizingMode", into: UIImage.ResizingMode.self, forModel: self, group: .appearance)
34 | .appendEnum(keyPath: "imageOrientation", into: UIImage.Orientation.self, forModel: self, group: .appearance)
35 |
36 | coordinator.appendDynamic(keyPaths: [
37 | "scale", "size", "capInsets", "alignmentRectInsets"
38 | ], forModel: self, in: .layout)
39 |
40 | super.preparePeek(with: coordinator)
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/UIImageView+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UIImageView {
26 |
27 | open override func preparePeek(with coordinator: Coordinator) {
28 | coordinator.appendDynamic(keyPaths: [
29 | "image", "highlightedImage"
30 | ], forModel: self, in: .appearance)
31 |
32 | coordinator.appendDynamic(keyPaths: [
33 | "animationDuration", "animationRepeatCount"
34 | ], forModel: self, in: .behaviour)
35 |
36 | coordinator.appendDynamic(keyPaths: [
37 | "isAnimating", "highlighted"
38 | ], forModel: self, in: .states)
39 |
40 | super.preparePeek(with: coordinator)
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/UILabel+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UILabel {
26 |
27 | open override func preparePeek(with coordinator: Coordinator) {
28 | coordinator.appendDynamic(keyPaths: [
29 | "text",
30 | "attributedText",
31 | ], forModel: self, in: .typography)
32 |
33 | (coordinator as? SwiftCoordinator)?
34 | .appendEnum(keyPath: "lineBreakMode", into: NSLineBreakMode.self, forModel: self, group: .behaviour)
35 | .appendEnum(keyPath: "textAlignment", into: NSTextAlignment.self, forModel: self, group: .typography)
36 |
37 | coordinator.appendDynamic(keyPaths: ["adjustsFontSizeToFitWidth"], forModel: self, in: .behaviour)
38 |
39 | coordinator.appendDynamic(keyPaths: [
40 | "textColor",
41 | "highlightedTextColor",
42 | "font",
43 | "minimumScaleFactor",
44 | ], forModel: self, in: .typography)
45 |
46 | coordinator.appendDynamic(keyPaths: ["preferredMaxLayoutWidth"], forModel: self, in: .layout)
47 |
48 | coordinator.appendDynamic(keyPaths: [
49 | "numberOfLines"
50 | ], forModel: self, in: .appearance)
51 |
52 | coordinator.appendDynamic(keyPaths: [
53 | "enabled",
54 | "highlighted"
55 | ], forModel: self, in: .states)
56 |
57 | coordinator.appendDynamic(keyPaths: [
58 | "shadowColor",
59 | "shadowOffset"
60 | ], forModel: self, in: .shadow)
61 |
62 | super.preparePeek(with: coordinator)
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/UINavigationBar+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UINavigationBar {
26 |
27 | open override func preparePeek(with coordinator: Coordinator) {
28 | coordinator.appendDynamic(keyPaths: [
29 | "barTintColor", "translucent", "shadowImage"
30 | ], forModel: self, in: .appearance)
31 |
32 | (coordinator as? SwiftCoordinator)?
33 | .appendEnum(keyPath: "barStyle", into: UIBarStyle.self, forModel: self, group: .appearance)
34 |
35 | super.preparePeek(with: coordinator)
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/UIPageControl+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UIPageControl {
26 |
27 | open override func preparePeek(with coordinator: Coordinator) {
28 | coordinator.appendDynamic(keyPaths: [
29 | "pageIndicatorTintColor", "currentPageIndicatorTintColor"
30 | ], forModel: self, in: .appearance)
31 |
32 | coordinator.appendDynamic(keyPaths: [
33 | "numberOfPages", "currentPage"
34 | ], forModel: self, in: .states)
35 |
36 | coordinator.appendDynamic(keyPaths: [
37 | "hidesForSinglePage", "defersCurrentPageDisplay"
38 | ], forModel: self, in: .behaviour)
39 |
40 | super.preparePeek(with: coordinator)
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/UIPicker+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UIPickerView {
26 |
27 | open override func preparePeek(with coordinator: Coordinator) {
28 | coordinator.appendDynamic(keyPaths: ["showsSelectionIndicator"], forModel: self, in: .behaviour)
29 |
30 | super.preparePeek(with: coordinator)
31 | }
32 |
33 | }
34 |
35 | extension UIDatePicker {
36 |
37 | open override func preparePeek(with coordinator: Coordinator) {
38 | coordinator.appendDynamic(keyPaths: [
39 | "date", "minimumDate", "maximumDate", "countDownDuration", "minuteInterval"
40 | ], forModel: self, in: .appearance)
41 |
42 | (coordinator as? SwiftCoordinator)?
43 | .appendEnum(keyPath: "datePickerMode", into: UIDatePicker.Mode.self, forModel: self, group: .appearance)
44 |
45 | super.preparePeek(with: coordinator)
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/UIProgressView+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UIProgressView {
26 |
27 | open override func preparePeek(with coordinator: Coordinator) {
28 | coordinator.appendDynamic(keyPaths: [
29 | "trackTintColor", "progressTintColor",
30 | "trackImage", "progressImage"
31 | ], forModel: self, in: .appearance)
32 |
33 | coordinator.appendDynamic(keyPaths: [
34 | "progress",
35 | ], forModel: self, in: .general)
36 |
37 | super.preparePeek(with: coordinator)
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/UIScreen+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UIScreen {
26 |
27 | open override func preparePeek(with coordinator: Coordinator) {
28 | coordinator.appendDynamic(keyPaths: [
29 | "wantsSoftwareDimming",
30 | "brightness"
31 | ], forModel: self, in: .appearance)
32 |
33 | coordinator.appendDynamic(keyPaths: [
34 | "applicationFrame",
35 | "bounds",
36 | "currentMode.size",
37 | "scale",
38 | "nativeScale",
39 | "currentMode.pixelAspectRatio"
40 | ], forModel: self, in: .layout)
41 |
42 | super.preparePeek(with: coordinator)
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/UIScrollView+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | extension UIScrollView {
26 |
27 | open override func preparePeek(with coordinator: Coordinator) {
28 | coordinator.appendDynamic(keyPaths: [
29 | "zoomScale",
30 | "minimumZoomScale",
31 | "maximumZoomScale",
32 | "bounces",
33 | "bouncesZoom",
34 | "alwaysBounceHorizontal",
35 | "alwaysBounceVertical",
36 | ], forModel: self, in: .appearance)
37 |
38 | (coordinator as? SwiftCoordinator)?
39 | .appendEnum(keyPath: "indicatorStyle", into: UIScrollView.IndicatorStyle.self, forModel: self, group: .appearance)
40 | .appendEnum(keyPath: "keyboardDismissMode", into: UIScrollView.KeyboardDismissMode.self, forModel: self, group: .behaviour)
41 |
42 | coordinator.appendDynamic(keyPaths: [
43 | "contentOffset", "contentSize", "contentInset", "scrollIndicatorInsets"
44 | ], forModel: self, in: .layout)
45 |
46 | coordinator.appendDynamic(keyPaths: [
47 | "showsHorizontalScrollIndicator",
48 | "showsVerticalScrollIndicator",
49 | "scrollEnabled",
50 | "scrollsToTop",
51 | "pagingEnabled",
52 | "decelerationRate",
53 | "directionalLockEnabled"
54 | ], forModel: self, in: .behaviour)
55 |
56 | super.preparePeek(with: coordinator)
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/Pod/Classes/Peekable/UISegmentedControl+Peekable.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | internal final class SegmentItem: NSObject {
26 |
27 | override var description: String {
28 | return title ?? ""
29 | }
30 |
31 | @objc var enabled: Bool = false
32 | @objc var title: String?
33 | @objc var width: CGFloat = 0
34 | @objc var image: UIImage?
35 | @objc var contentOffset: CGSize = CGSize.zero
36 |
37 | internal override var isLeaf: Bool { return false }
38 |
39 | override func preparePeek(with coordinator: Coordinator) {
40 | if let image = image {
41 | coordinator.appendPreview(image: image, forModel: self)
42 | }
43 |
44 | coordinator.appendDynamic(keyPaths: [
45 | "title", "image"
46 | ], forModel: self, in: .appearance)
47 |
48 | coordinator.appendDynamic(keyPaths: [
49 | "contentOffset", "width"
50 | ], forModel: self, in: .layout)
51 |
52 | coordinator.appendDynamic(keyPaths: [
53 | "enabled"
54 | ], forModel: self, in: .states)
55 |
56 | super.preparePeek(with: coordinator)
57 | }
58 |
59 | }
60 |
61 | extension UISegmentedControl {
62 |
63 | var segments: [SegmentItem]? {
64 | var segments = [SegmentItem]()
65 |
66 | for index in 0.. Any? {
37 | guard let number = value as? NSNumber, !number.isBool() else {
38 | return nil
39 | }
40 |
41 | if number.isFloat() {
42 | return NumberTransformer.floatFormatter.string(from: number)!
43 | }
44 |
45 | return "\(number)"
46 | }
47 |
48 | override class func allowsReverseTransformation() -> Bool {
49 | return false
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/Pod/Classes/Transformers/NSValue+Transformer.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | /// Creates string representations of common values, e.g. CGPoint, CGRect, etc...
26 | final class ValueTransformer: Foundation.ValueTransformer {
27 |
28 | fileprivate static var floatFormatter: NumberFormatter {
29 | let formatter = NumberFormatter()
30 | formatter.maximumFractionDigits = 1
31 | formatter.minimumFractionDigits = 0
32 | formatter.minimumIntegerDigits = 1
33 | formatter.roundingIncrement = 0.5
34 | return formatter
35 | }
36 |
37 | override func transformedValue(_ value: Any?) -> Any? {
38 | if let value = value as? NSValue {
39 | let type = String(cString: value.objCType)
40 |
41 | if type.hasPrefix("{CGRect") {
42 | let rect = value.cgRectValue
43 | return
44 | "(\(ValueTransformer.floatFormatter.string(from: NSNumber(value: Float(rect.minX)))!), " +
45 | "\(ValueTransformer.floatFormatter.string(from: NSNumber(value: Float(rect.minY)))!)), " +
46 | "(\(ValueTransformer.floatFormatter.string(from: NSNumber(value: Float(rect.width)))!), " +
47 | "\(ValueTransformer.floatFormatter.string(from: NSNumber(value: Float(rect.height)))!))"
48 | }
49 |
50 | if type.hasPrefix("{CGPoint") {
51 | let point = value.cgPointValue
52 | return "(\(ValueTransformer.floatFormatter.string(from: NSNumber(value: Float(point.x)))!), \(ValueTransformer.floatFormatter.string(from: NSNumber(value: Float(point.y)))!))"
53 | }
54 |
55 | if type.hasPrefix("{UIEdgeInset") {
56 | let insets = value.uiEdgeInsetsValue
57 | return
58 | "(\(ValueTransformer.floatFormatter.string(from: NSNumber(value: Float(insets.left)))!), " +
59 | "\(ValueTransformer.floatFormatter.string(from: NSNumber(value: Float(insets.top)))!), " +
60 | "\(ValueTransformer.floatFormatter.string(from: NSNumber(value: Float(insets.right)))!), " +
61 | "\(ValueTransformer.floatFormatter.string(from: NSNumber(value: Float(insets.bottom)))!))"
62 | }
63 |
64 | if type.hasPrefix("{UIOffset") {
65 | let offset = value.uiOffsetValue
66 | return "(\(ValueTransformer.floatFormatter.string(from: NSNumber(value: Float(offset.horizontal)))!), \(ValueTransformer.floatFormatter.string(from: NSNumber(value: Float(offset.vertical)))!))"
67 | }
68 |
69 | if type.hasPrefix("{CGSize") {
70 | let size = value.cgSizeValue
71 | return "(\(ValueTransformer.floatFormatter.string(from: NSNumber(value: Float(size.width)))!), \(ValueTransformer.floatFormatter.string(from: NSNumber(value: Float(size.height)))!))"
72 | }
73 | }
74 |
75 | return nil
76 | }
77 |
78 | override class func allowsReverseTransformation() -> Bool {
79 | return false
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/Pod/Classes/Transformers/UIColor+Transformer.swift:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 23/04/2016 Shaps
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in
12 | all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | THE SOFTWARE.
21 | */
22 |
23 | import UIKit
24 |
25 | /// Creates a HEX string representation of a UIColor
26 | final class ColorTransformer: Foundation.ValueTransformer {
27 |
28 | override func transformedValue(_ value: Any?) -> Any? {
29 | if let value = value as? UIColor, let color = Color(system: value) {
30 | if color == .clear {
31 | return "Clear"
32 | }
33 |
34 | if color.cgColor.pattern != nil {
35 | return "Pattern"
36 | }
37 |
38 | return color.rgba.alpha == 0
39 | ? "Transparent"
40 | : value.peek_HEX
41 | }
42 |
43 | if CFGetTypeID(value as CFTypeRef) == CGColor.typeID {
44 | // swiftlint:disable force_cast
45 | let color = Color(cgColor: value as! CGColor)
46 | return color?.rgba.alpha == 0 ? "Clear" : color?.system.peek_HEX
47 | }
48 |
49 | return "none"
50 | }
51 |
52 | override class func allowsReverseTransformation() -> Bool {
53 | return false
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/preview.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/preview.gif
--------------------------------------------------------------------------------
/preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaps80/Peek/057f0f60fc0e07c0513ac2e508d83f43be860cd3/preview.jpg
--------------------------------------------------------------------------------
/pull_request_template.md:
--------------------------------------------------------------------------------
1 | **Checklist**
2 |
3 | - Latest changes from `develop` have been merged
4 | - Conflicts have been resolved
5 | - The branch is pointing to `develop`
6 | - SwiftLint hasn't reported any issues.
7 |
--------------------------------------------------------------------------------