├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Gemfile ├── Gemfile.lock ├── Helpers └── PlaygroundSupport.swift ├── LICENSE ├── Package.swift ├── README.md ├── ShortcutsSwift.playgroundbook └── Contents │ ├── Chapters │ └── Chapter1.playgroundchapter │ │ ├── Manifest.plist │ │ └── Pages │ │ ├── Page1.playgroundpage │ │ ├── Contents.swift │ │ ├── LiveView.swift │ │ └── Manifest.plist │ │ └── Page2.playgroundpage │ │ ├── Contents.swift │ │ ├── LiveView.swift │ │ └── Manifest.plist │ ├── Manifest.plist │ ├── PrivateResources │ └── Cover.png │ └── Sources │ ├── Action.swift │ ├── ActionOutput.swift │ ├── Actions │ ├── AskForInput.swift │ ├── Calculate.swift │ ├── ChangeCase.swift │ ├── ChooseFromMenu.swift │ ├── Comment.swift │ ├── Conditional.swift │ ├── CopyToClipboard.swift │ ├── Dictionary.swift │ ├── GetBatteryLevel.swift │ ├── List.swift │ ├── Number.swift │ ├── Repeat.swift │ ├── ReplaceText.swift │ ├── RunScene.swift │ ├── SetLowPowerMode.swift │ ├── Share.swift │ ├── ShowResult.swift │ └── SplitText.swift │ ├── Aggrandizement.swift │ ├── Attachment.swift │ ├── BaseTypes.swift │ ├── BuildShortcut.swift │ ├── InterpolatedText.swift │ ├── UI │ └── ShortcutShareViewController.swift │ └── Variable.swift ├── ShortcutsSwift.xcodeproj ├── ShortcutsSwift-Info.plist ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── ShortcutsSwift.xcscheme ├── Tests ├── AggrandizementTests.swift ├── Info.plist └── ShortcutsSwiftTests.swift ├── azure-pipelines.yml ├── banner.png ├── fastlane ├── Fastfile └── README.md ├── feed.json └── preview.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | # Package.resolved 41 | .build/ 42 | 43 | # CocoaPods 44 | # 45 | # We recommend against adding the Pods directory to your .gitignore. However 46 | # you should judge for yourself, the pros and cons are mentioned at: 47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 48 | # 49 | # Pods/ 50 | # 51 | # Add this line if you want to avoid checking in source code from the Xcode workspace 52 | # *.xcworkspace 53 | 54 | # Carthage 55 | # 56 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 57 | # Carthage/Checkouts 58 | 59 | Carthage/Build 60 | 61 | # fastlane 62 | # 63 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 64 | # screenshots whenever they are needed. 65 | # For more information about the recommended setup visit: 66 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 67 | 68 | fastlane/report.xml 69 | fastlane/Preview.html 70 | fastlane/screenshots/**/*.png 71 | fastlane/test_output 72 | 73 | # Code Injection 74 | # 75 | # After new code Injection tools there's a generated folder /iOSInjectionProject 76 | # https://github.com/johnno1962/injectionforxcode 77 | 78 | iOSInjectionProject/ 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 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at me@a2.io. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to _ShortcutsSwift_ 2 | 3 | The following is a set of guidelines for contributing to _ShortcutsSwift_ on GitHub. 4 | 5 | > Above all, thank you for your interest in the project and for taking the time to contribute! 👍 6 | 7 | ## I want to report a problem or ask a question 8 | 9 | Before submitting a new GitHub issue, please make sure to 10 | 11 | - Check out the documentation. 12 | - Read the usage guide on [the README](https://github.com/a2/shortcuts-swift). 13 | - Search for [existing GitHub issues](https://github.com/a2/shortcuts-swift/issues). 14 | 15 | If the above doesn't help, please [submit an issue](https://github.com/a2/shortcuts-swift/issues) on GitHub. 16 | 17 | ## I want to contribute to _ShortcutsSwift_ 18 | 19 | ### Prerequisites 20 | 21 | To develop _ShortcutsSwift_, you will need to use an Xcode version compatible with the Swift version specified in the [README](https://github.com/a2/shortcuts-swift/#contributing). 22 | 23 | ### Checking out the repository 24 | 25 | - Click the “Fork” button in the upper right corner of repo 26 | - Clone your fork: 27 | - `git clone https://github.com//shortcuts-swift.git` 28 | - Create a new branch to work on: 29 | - `git checkout -b ` 30 | - A good name for a branch describes the thing you’ll be working on, e.g. `add-action`, `fix-bug`, etc. 31 | 32 | That’s it! Now you’re ready to work on _ShortcutsSwift_. Open the `ShortcutsSwift` project to start coding. 33 | 34 | ### Things to keep in mind 35 | 36 | - Always document new public methods and properties 37 | 38 | ### Testing your local changes 39 | 40 | Before opening a pull request, please make sure your changes don't break things. 41 | 42 | - The framework and tests should build without warnings 43 | - The playground book should run without issues on iPad. 44 | 45 | ### Submitting the PR 46 | 47 | When the coding is done and you’ve finished testing your changes, you are ready to submit the PR to the [main repo](https://github.com/a2/shortcuts-swift). Some best practices are: 48 | 49 | - Use a descriptive title 50 | - Link the issues that are related to your PR in the body 51 | 52 | ## Code of Conduct 53 | 54 | Help us keep _ShortcutsSwift_ open and inclusive. Please read and follow our [Code of Conduct](CODE_OF_CONDUCT.md). 55 | 56 | ## License 57 | 58 | This project is licensed under the terms of the MIT license. See the [LICENSE](LICENSE) file. 59 | 60 | _These contribution guidelines were adapted from [_fastlane_](https://github.com/fastlane/fastlane) guides._ 61 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "fastlane" 4 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.0) 5 | addressable (2.5.2) 6 | public_suffix (>= 2.0.2, < 4.0) 7 | atomos (0.1.3) 8 | babosa (1.0.2) 9 | claide (1.0.2) 10 | colored (1.2) 11 | colored2 (3.1.2) 12 | commander-fastlane (4.4.6) 13 | highline (~> 1.7.2) 14 | declarative (0.0.10) 15 | declarative-option (0.1.0) 16 | digest-crc (0.4.1) 17 | domain_name (0.5.20180417) 18 | unf (>= 0.0.5, < 1.0.0) 19 | dotenv (2.5.0) 20 | emoji_regex (0.1.1) 21 | excon (0.62.0) 22 | faraday (0.15.4) 23 | multipart-post (>= 1.2, < 3) 24 | faraday-cookie_jar (0.0.6) 25 | faraday (>= 0.7.4) 26 | http-cookie (~> 1.0.0) 27 | faraday_middleware (0.12.2) 28 | faraday (>= 0.7.4, < 1.0) 29 | fastimage (2.1.5) 30 | fastlane (2.112.0) 31 | CFPropertyList (>= 2.3, < 4.0.0) 32 | addressable (>= 2.3, < 3.0.0) 33 | babosa (>= 1.0.2, < 2.0.0) 34 | bundler (>= 1.12.0, < 2.0.0) 35 | colored 36 | commander-fastlane (>= 4.4.6, < 5.0.0) 37 | dotenv (>= 2.1.1, < 3.0.0) 38 | emoji_regex (~> 0.1) 39 | excon (>= 0.45.0, < 1.0.0) 40 | faraday (~> 0.9) 41 | faraday-cookie_jar (~> 0.0.6) 42 | faraday_middleware (~> 0.9) 43 | fastimage (>= 2.1.0, < 3.0.0) 44 | gh_inspector (>= 1.1.2, < 2.0.0) 45 | google-api-client (>= 0.21.2, < 0.24.0) 46 | google-cloud-storage (>= 1.15.0, < 2.0.0) 47 | highline (>= 1.7.2, < 2.0.0) 48 | json (< 3.0.0) 49 | mini_magick (~> 4.5.1) 50 | multi_json 51 | multi_xml (~> 0.5) 52 | multipart-post (~> 2.0.0) 53 | plist (>= 3.1.0, < 4.0.0) 54 | public_suffix (~> 2.0.0) 55 | rubyzip (>= 1.2.2, < 2.0.0) 56 | security (= 0.1.3) 57 | simctl (~> 1.6.3) 58 | slack-notifier (>= 2.0.0, < 3.0.0) 59 | terminal-notifier (>= 1.6.2, < 2.0.0) 60 | terminal-table (>= 1.4.5, < 2.0.0) 61 | tty-screen (>= 0.6.3, < 1.0.0) 62 | tty-spinner (>= 0.8.0, < 1.0.0) 63 | word_wrap (~> 1.0.0) 64 | xcodeproj (>= 1.6.0, < 2.0.0) 65 | xcpretty (~> 0.3.0) 66 | xcpretty-travis-formatter (>= 0.0.3) 67 | gh_inspector (1.1.3) 68 | google-api-client (0.23.9) 69 | addressable (~> 2.5, >= 2.5.1) 70 | googleauth (>= 0.5, < 0.7.0) 71 | httpclient (>= 2.8.1, < 3.0) 72 | mime-types (~> 3.0) 73 | representable (~> 3.0) 74 | retriable (>= 2.0, < 4.0) 75 | signet (~> 0.9) 76 | google-cloud-core (1.2.7) 77 | google-cloud-env (~> 1.0) 78 | google-cloud-env (1.0.5) 79 | faraday (~> 0.11) 80 | google-cloud-storage (1.15.0) 81 | digest-crc (~> 0.4) 82 | google-api-client (~> 0.23) 83 | google-cloud-core (~> 1.2) 84 | googleauth (~> 0.6.2) 85 | googleauth (0.6.7) 86 | faraday (~> 0.12) 87 | jwt (>= 1.4, < 3.0) 88 | memoist (~> 0.16) 89 | multi_json (~> 1.11) 90 | os (>= 0.9, < 2.0) 91 | signet (~> 0.7) 92 | highline (1.7.10) 93 | http-cookie (1.0.3) 94 | domain_name (~> 0.5) 95 | httpclient (2.8.3) 96 | json (2.1.0) 97 | jwt (2.1.0) 98 | memoist (0.16.0) 99 | mime-types (3.2.2) 100 | mime-types-data (~> 3.2015) 101 | mime-types-data (3.2018.0812) 102 | mini_magick (4.5.1) 103 | multi_json (1.13.1) 104 | multi_xml (0.6.0) 105 | multipart-post (2.0.0) 106 | nanaimo (0.2.6) 107 | naturally (2.2.0) 108 | os (1.0.0) 109 | plist (3.5.0) 110 | public_suffix (2.0.5) 111 | representable (3.0.4) 112 | declarative (< 0.1.0) 113 | declarative-option (< 0.2.0) 114 | uber (< 0.2.0) 115 | retriable (3.1.2) 116 | rouge (2.0.7) 117 | rubyzip (1.2.2) 118 | security (0.1.3) 119 | signet (0.11.0) 120 | addressable (~> 2.3) 121 | faraday (~> 0.9) 122 | jwt (>= 1.5, < 3.0) 123 | multi_json (~> 1.10) 124 | simctl (1.6.5) 125 | CFPropertyList 126 | naturally 127 | slack-notifier (2.3.2) 128 | terminal-notifier (1.8.0) 129 | terminal-table (1.8.0) 130 | unicode-display_width (~> 1.1, >= 1.1.1) 131 | tty-cursor (0.6.0) 132 | tty-screen (0.6.5) 133 | tty-spinner (0.9.0) 134 | tty-cursor (~> 0.6.0) 135 | uber (0.1.0) 136 | unf (0.1.4) 137 | unf_ext 138 | unf_ext (0.0.7.5) 139 | unicode-display_width (1.4.1) 140 | word_wrap (1.0.0) 141 | xcodeproj (1.7.0) 142 | CFPropertyList (>= 2.3.3, < 4.0) 143 | atomos (~> 0.1.3) 144 | claide (>= 1.0.2, < 2.0) 145 | colored2 (~> 3.1) 146 | nanaimo (~> 0.2.6) 147 | xcpretty (0.3.0) 148 | rouge (~> 2.0.7) 149 | xcpretty-travis-formatter (1.0.0) 150 | xcpretty (~> 0.2, >= 0.0.7) 151 | 152 | PLATFORMS 153 | ruby 154 | 155 | DEPENDENCIES 156 | fastlane 157 | 158 | BUNDLED WITH 159 | 1.16.2 160 | -------------------------------------------------------------------------------- /Helpers/PlaygroundSupport.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | public indirect enum PlaygroundValue { 4 | case boolean(Bool) 5 | case data(Data) 6 | case date(Date) 7 | case floatingPoint(Double) 8 | case integer(Int) 9 | case string(String) 10 | case array([PlaygroundValue]) 11 | case dictionary([String: PlaygroundValue]) 12 | } 13 | 14 | public protocol PlaygroundLiveViewMessageHandler { 15 | func receive(_ message: PlaygroundValue) 16 | } 17 | 18 | public protocol PlaygroundLiveViewSafeAreaContainer { 19 | var liveViewSafeAreaGuide: UILayoutGuide { get } 20 | } 21 | 22 | extension UIViewController { 23 | public var liveViewSafeAreaGuide: UILayoutGuide { 24 | return view.safeAreaLayoutGuide 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Shortcuts Swift Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:4.2 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "ShortcutsSwift", 8 | products: [ 9 | .library( 10 | name: "ShortcutsSwift", 11 | targets: ["ShortcutsSwift"]), 12 | ], 13 | targets: [ 14 | .target( 15 | name: "ShortcutsSwift", 16 | path: "ShortcutsSwift.playgroundbook/Contents/Sources/", 17 | exclude: ["UI"]), 18 | .testTarget( 19 | name: "ShortcutsSwiftTests", 20 | dependencies: ["ShortcutsSwift"], 21 | path: "Tests") 22 | ] 23 | ) 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | *This repository has been replaced with [SwiftShortcuts](https://github.com/a2/swift-shortcuts), and is archived for reference.* 2 | 3 | ![Banner](https://raw.githubusercontent.com/a2/shortcuts-swift/master/banner.png) 4 | 5 | # Shortcuts Swift 6 | 7 | [![Build Status](https://dev.azure.com/pandamonia/shortcuts-swift/_apis/build/status/a2.shortcuts-swift?branchName=master)](https://dev.azure.com/pandamonia/shortcuts-swift/_build/latest?definitionId=3?branchName=master) 8 | 9 | [Subscription feed link](https://raw.githubusercontent.com/a2/shortcuts-swift/master/feed.json) or click [here](https://developer.apple.com/ul/sp0?url=https://raw.githubusercontent.com/a2/shortcuts-swift/master/feed.json) on your iPad with Swift Playgrounds 2 installed. 10 | 11 | ## Example 12 | 13 | ### Warn for Low Battery Level 14 | 15 | ```swift 16 | let batteryLevel = actionOutput() 17 | let shortcut = buildShortcut( 18 | comment("This Shortcut was generated in Swift.") + 19 | getBatteryLevel().savingOutput(to: batteryLevel) + 20 | ifLessThan(20, ifTrue: ( 21 | setLowPowerMode(true) + 22 | showResult("Your battery is at \(batteryLevel)%, you might want to charge it.") 23 | ), ifFalse: ( 24 | showResult("Your battery is at \(batteryLevel)%, you're probably fine for now.") 25 | )) 26 | ) 27 | ``` 28 | 29 | ### Clap Along 30 | 31 | ```swift 32 | let shortcut = buildShortcut( 33 | comment("This Shortcut was generated in Swift.") + 34 | ask(question: "WHAT 👏 DO 👏 YOU 👏 WANT 👏 TO 👏 SAY") + 35 | changeCase(to: .uppercase) + 36 | replaceText("[\\s]", replaceWith: " 👏 ", regularExpression: true) + 37 | chooseFromMenu(items: [ 38 | ("Share", share()), 39 | ("Copy to Clipboard", copyToClipboard()), 40 | ]) 41 | ) 42 | ``` 43 | ## Swift Package Manager 44 | 45 | ```swift 46 | .package(url: "https://github.com/a2/shortcuts-swift", from: "1.0.0") 47 | ``` 48 | 49 | ## Contributing 50 | 51 | Please read the [Contributions Guide](CONTRIBUTING.md) and the [Code of Conduct](CODE_OF_CONDUCT.md) before getting started. You will need Xcode 10 or newer to build the project. 52 | 53 | ## Authors 54 | 55 | [Alexsander Akers](https://github.com/a2) and [Alexis Aubry](https://github.com/alexaubry) 56 | 57 | ## License 58 | 59 | Shortcuts Swift is available under the MIT license. See the LICENSE file for more info. 60 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Manifest.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Name 6 | Shortcuts Swift 7 | Pages 8 | 9 | Page1.playgroundpage 10 | Page2.playgroundpage 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | let batteryLevel = actionOutput() 2 | let shortcut = buildShortcut( 3 | comment("This Shortcut was generated in Swift.") + 4 | getBatteryLevel().savingOutput(to: batteryLevel) + 5 | ifLessThan(20, ifTrue: ( 6 | setLowPowerMode(true) + 7 | showResult("Your battery is at \(batteryLevel)%, you might want to charge it.") 8 | ), ifFalse: ( 9 | showResult("Your battery is at \(batteryLevel)%, you're probably fine for now.") 10 | )) 11 | ) 12 | 13 | shareShortcut(shortcut, named: "Warn for Low Battery Level") 14 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/LiveView.swift: -------------------------------------------------------------------------------- 1 | import PlaygroundSupport 2 | import UIKit 3 | 4 | let viewController = ShortcutShareViewController() 5 | PlaygroundPage.current.liveView = viewController 6 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page1.playgroundpage/Manifest.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Name 6 | Warn for Low Battery Level 7 | LiveViewEdgeToEdge 8 | 9 | LiveViewMode 10 | VisibleByDefault 11 | 12 | 13 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page2.playgroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | let shortcut = buildShortcut( 2 | comment("This Shortcut was generated in Swift.") + 3 | ask(question: "WHAT 👏 DO 👏 YOU 👏 WANT 👏 TO 👏 SAY") + 4 | changeCase(to: .uppercase) + 5 | replaceText("[\\s]", replaceWith: " 👏 ", regularExpression: true) + 6 | chooseFromMenu(items: [ 7 | ("Share", share()), 8 | ("Copy to Clipboard", copyToClipboard()), 9 | ]) 10 | ) 11 | 12 | shareShortcut(shortcut, named: "Clap Along") 13 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page2.playgroundpage/LiveView.swift: -------------------------------------------------------------------------------- 1 | import PlaygroundSupport 2 | import UIKit 3 | 4 | let viewController = ShortcutShareViewController() 5 | PlaygroundPage.current.liveView = viewController 6 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Chapters/Chapter1.playgroundchapter/Pages/Page2.playgroundpage/Manifest.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Name 6 | Clap Along 7 | LiveViewEdgeToEdge 8 | 9 | LiveViewMode 10 | VisibleByDefault 11 | 12 | 13 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Manifest.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Name 6 | Shortcuts Swift 7 | DevelopmentRegion 8 | en-US 9 | ContentIdentifier 10 | io.a2.shortcuts-swift 11 | ContentVersion 12 | 1.0 13 | ImageReference 14 | Cover.png 15 | DeploymentTarget 16 | ios12.0 17 | SwiftVersion 18 | 4.2 19 | MinimumSwiftPlaygroundsVersion 20 | 1.6 21 | Version 22 | 3.0 23 | Chapters 24 | 25 | Chapter1.playgroundchapter 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/PrivateResources/Cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a2/shortcuts-swift/45f825c584dccafb0a1cf2fa836404fbaf49ecaf/ShortcutsSwift.playgroundbook/Contents/PrivateResources/Cover.png -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Action.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct Action { 4 | public var identifier: String 5 | public var parameters: PropertyList 6 | 7 | public init(identifier: String, parameters: PropertyList) { 8 | self.identifier = identifier 9 | self.parameters = parameters 10 | } 11 | 12 | var propertyList: PropertyList { 13 | return [ 14 | "WFWorkflowActionIdentifier": identifier, 15 | "WFWorkflowActionParameters": parameters 16 | ] 17 | } 18 | } 19 | 20 | public protocol ActionContainer { 21 | var actions: [Action] { get } 22 | } 23 | 24 | extension Array: ActionContainer where Element == Action { 25 | public var actions: [Action] { 26 | return self 27 | } 28 | } 29 | 30 | extension Action: ActionContainer { 31 | public var actions: [Action] { 32 | return [self] 33 | } 34 | } 35 | 36 | public func + (lhs: ActionContainer, rhs: ActionContainer) -> ActionContainer { 37 | let leftActions = lhs.actions 38 | let rightActions = rhs.actions 39 | var result = [Action]() 40 | result.reserveCapacity(leftActions.count + rightActions.count) 41 | result.append(contentsOf: leftActions) 42 | result.append(contentsOf: rightActions) 43 | return result 44 | } 45 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/ActionOutput.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | * An action that supports output. See `ActionOutputProviding` for instructions 5 | * about saving to a variable. 6 | */ 7 | public typealias ActionWithOutput = ActionContainer & ActionOutputProviding 8 | 9 | /** 10 | * A protocol for actions that support saving their output to a variable, and 11 | * returning the updated action. 12 | */ 13 | public protocol ActionOutputProviding { 14 | /** 15 | * Saves the output of the action to a variable. 16 | * - parameter variable: The pointer to the variable to use to save the output. 17 | * - returns: The action to use in the builder. 18 | * 19 | * Example usage: 20 | * ~~~swift 21 | * let batteryLevel = actionOutput() 22 | * let shortcut = buildShortcut( 23 | * getBatteryLevel().savingOutput(to: batteryLevel) 24 | * ) 25 | * ~~~ 26 | */ 27 | 28 | func savingOutput(to variable: ActionOutputVariable) -> ActionContainer 29 | } 30 | 31 | extension Action: ActionOutputProviding { 32 | public func savingOutput(to variable: ActionOutputVariable) -> ActionContainer { 33 | var parameters = self.parameters 34 | parameters["CustomOutputName"] = variable.value.outputName 35 | parameters["UUID"] = variable.value.outputUUID?.uuidString 36 | 37 | return Action(identifier: self.identifier, parameters: parameters) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/AskForInput.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func ask(question: String, defaultAnswer: String = "") -> ActionWithOutput { 4 | return Action(identifier: "is.workflow.actions.ask", parameters: [ 5 | "WFAskActionPrompt": withInterpolatedText(question), 6 | "WFAskActionDefaultAnswer": withInterpolatedText(defaultAnswer), 7 | ]) 8 | } 9 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/Calculate.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum MathOperation: String { 4 | case add = "+" 5 | case substract = "-" 6 | case multiply = "×" 7 | case divide = "÷" 8 | } 9 | 10 | public func calculate(_ operation: MathOperation, value: Number) -> ActionWithOutput { 11 | let parameters: PropertyList = [ 12 | "WFMathOperation": operation.rawValue, 13 | "WFMathOperand": value 14 | ] 15 | return Action(identifier: "is.workflow.actions.math", parameters: parameters) 16 | } 17 | 18 | public func calculate(_ operation: MathOperation, with variable: Variable) -> ActionWithOutput { 19 | let parameters: PropertyList = [ 20 | "WFMathOperation": operation.rawValue, 21 | "WFMathOperand": variable.propertyList 22 | ] 23 | return Action(identifier: "is.workflow.actions.math", parameters: parameters) 24 | } 25 | 26 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/ChangeCase.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum TextCase { 4 | case uppercase 5 | case lowercase 6 | case capitalizeEveryWord 7 | case capitalizeWithTitleCase 8 | case capitalizeWithSentenceCase 9 | case capitalizeWithAlternatingCase 10 | case askWhenRun 11 | 12 | var parameterValue: Any { 13 | switch self { 14 | case .uppercase: 15 | return "UPPERCASE" 16 | case .lowercase: 17 | return "lowercase" 18 | case .capitalizeEveryWord: 19 | return "Capitalize Every Word" 20 | case .capitalizeWithTitleCase: 21 | return "Capitalize with Title Case" 22 | case .capitalizeWithSentenceCase: 23 | return "Capitalize with sentence case." 24 | case .capitalizeWithAlternatingCase: 25 | return "cApItAlIzE wItH aLtErNaTiNg CaSe." 26 | case .askWhenRun: 27 | return [ 28 | "Value": ["Type": "Ask"] as PropertyList, 29 | "WFSerializationType": "WFTextTokenAttachment", 30 | ] as PropertyList 31 | } 32 | } 33 | } 34 | 35 | public func changeCase(to case: TextCase) -> ActionWithOutput { 36 | return Action(identifier: "is.workflow.actions.text.changecase", parameters: ["WFCaseType": `case`.parameterValue]) 37 | } 38 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/ChooseFromMenu.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func chooseFromMenu(prompt: String = "", items: [(label: String, actions: ActionContainer)] = []) -> ActionContainer { 4 | let groupingIdentifier = UUID().uuidString 5 | 6 | var result = [Action]() 7 | result.append(Action(identifier: "is.workflow.actions.choosefrommenu", parameters: [ 8 | "GroupingIdentifier": groupingIdentifier, 9 | "WFControlFlowMode": 0, 10 | "WFMenuItems": items.map { $0.label } as [String], 11 | "WFMenuPrompt": prompt, 12 | ])) 13 | 14 | for (label, actionContainer) in items { 15 | result.append(Action(identifier: "is.workflow.actions.choosefrommenu", parameters: [ 16 | "GroupingIdentifier": groupingIdentifier, 17 | "WFControlFlowMode": 1, 18 | "WFMenuItemTitle": label, 19 | ])) 20 | result.append(contentsOf: actionContainer.actions) 21 | } 22 | 23 | result.append(Action(identifier: "is.workflow.actions.choosefrommenu", parameters: [ 24 | "GroupingIdentifier": groupingIdentifier, 25 | "WFControlFlowMode": 2, 26 | ])) 27 | 28 | return result 29 | } 30 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/Comment.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func comment(_ text: String) -> ActionContainer { 4 | return Action(identifier: "is.workflow.actions.comment", parameters: ["WFCommentActionText": text]) 5 | } 6 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/Conditional.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum Relation { 4 | case equals 5 | case contains 6 | case greaterThan 7 | case lessThan 8 | 9 | var stringValue: String { 10 | switch self { 11 | case .equals: 12 | return "Equals" 13 | case .contains: 14 | return "Contains" 15 | case .greaterThan: 16 | return "Is Greater Than" 17 | case .lessThan: 18 | return "Is Less Than" 19 | } 20 | } 21 | } 22 | 23 | public enum Value { 24 | case number(Number) 25 | case string(String) 26 | } 27 | 28 | public func conditional(_ relation: Relation, _ value: Value, ifTrue: ActionContainer, ifFalse: ActionContainer?) -> ActionContainer { 29 | let groupingIdentifier = UUID().uuidString 30 | 31 | var result = [Action]() 32 | 33 | var startIfParameters: PropertyList = [ 34 | "WFControlFlowMode": 0, 35 | "GroupingIdentifier": groupingIdentifier, 36 | "WFCondition": relation.stringValue 37 | ] 38 | switch value { 39 | case .number(let number): 40 | startIfParameters["WFNumberValue"] = number 41 | case .string(let string): 42 | startIfParameters["WFConditionalActionString"] = string 43 | } 44 | result.append(Action(identifier: "is.workflow.actions.conditional", parameters: startIfParameters)) 45 | result.append(contentsOf: ifTrue.actions) 46 | 47 | if let ifFalse = ifFalse { 48 | result.append(Action(identifier: "is.workflow.actions.conditional", parameters: [ 49 | "WFControlFlowMode": 1, 50 | "GroupingIdentifier": groupingIdentifier 51 | ])) 52 | result.append(contentsOf: ifFalse.actions) 53 | } 54 | 55 | result.append(Action(identifier: "is.workflow.actions.conditional", parameters: [ 56 | "WFControlFlowMode": 2, 57 | "GroupingIdentifier": groupingIdentifier 58 | ])) 59 | 60 | return result 61 | } 62 | 63 | public func ifLessThan(_ number: Number, ifTrue: ActionContainer, ifFalse: ActionContainer?) -> ActionContainer { 64 | return conditional(.lessThan, .number(number), ifTrue: ifTrue, ifFalse: ifFalse) 65 | } 66 | 67 | public func ifGreaterThan(_ number: Number, ifTrue: ActionContainer, ifFalse: ActionContainer?) -> ActionContainer { 68 | return conditional(.lessThan, .number(number), ifTrue: ifTrue, ifFalse: ifFalse) 69 | } 70 | 71 | public func ifEqualTo(_ number: Number, ifTrue: ActionContainer, ifFalse: ActionContainer?) -> ActionContainer { 72 | return conditional(.equals, .number(number), ifTrue: ifTrue, ifFalse: ifFalse) 73 | } 74 | 75 | public func ifEqualTo(_ string: String, ifTrue: ActionContainer, ifFalse: ActionContainer?) -> ActionContainer { 76 | return conditional(.equals, .string(string), ifTrue: ifTrue, ifFalse: ifFalse) 77 | } 78 | 79 | public func ifContains(_ string: String, ifTrue: ActionContainer, ifFalse: ActionContainer?) -> ActionContainer { 80 | return conditional(.contains, .string(string), ifTrue: ifTrue, ifFalse: ifFalse) 81 | } 82 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/CopyToClipboard.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func copyToClipboard(localOnly: Bool = false, expireAt expiration: String = "") -> ActionContainer { 4 | return Action(identifier: "is.workflow.actions.setclipboard", parameters: [ 5 | "WFLocalOnly": localOnly, 6 | "WFExpirationDate": expiration, 7 | ]) 8 | } 9 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/Dictionary.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | enum ItemType: Int { 4 | case string = 0 5 | case dictionary = 1 6 | case array = 2 7 | case number = 3 8 | case boolean = 4 9 | } 10 | 11 | public enum DictionaryValue { 12 | case string(String) 13 | case number(Number) 14 | case boolean(Bool) 15 | case dictionary([String: DictionaryValue]) 16 | case array([DictionaryValue]) 17 | 18 | var propertyList: PropertyList { 19 | switch self { 20 | case .string(let string): 21 | return [ 22 | "WFItemType": ItemType.string.rawValue, 23 | "WFValue": [ 24 | "Value": ["string": string, "attachmentsByRange": [:]], 25 | "WFSerializationType": "WFTextTokenString" 26 | ] 27 | ] 28 | case .number(let number): 29 | return [ 30 | "WFItemType": ItemType.number.rawValue, 31 | "WFValue": [ 32 | "Value": ["string": "\(number)", "attachmentsByRange": [:]], 33 | "WFSerializationType": "WFTextTokenString" 34 | ] 35 | ] 36 | case .boolean(let bool): 37 | return [ 38 | "WFItemType": ItemType.boolean.rawValue, 39 | "WFValue": [ 40 | "Value": bool, 41 | "WFSerializationType": "WFNumberSubstitutableState" 42 | ] 43 | ] 44 | case .array(let values): 45 | return [ 46 | "WFItemType": ItemType.array.rawValue, 47 | "WFValue": [ 48 | "Value": values.map { $0.propertyList }, 49 | "WFSerializationType": "WFArrayParameterState" 50 | ] 51 | ] 52 | case .dictionary(let values): 53 | return [ 54 | "WFItemType": ItemType.dictionary.rawValue, 55 | "WFValue": [ 56 | "Value": serialize(values), 57 | "WFSerializationType": "WFDictionaryFieldValue", 58 | ] 59 | ] 60 | } 61 | } 62 | } 63 | 64 | extension DictionaryValue: ExpressibleByArrayLiteral { 65 | public init(arrayLiteral elements: DictionaryValue...) { 66 | self = .array(elements) 67 | } 68 | } 69 | 70 | extension DictionaryValue: ExpressibleByBooleanLiteral { 71 | public init(booleanLiteral value: Bool) { 72 | self = .boolean(value) 73 | } 74 | } 75 | 76 | extension DictionaryValue: ExpressibleByDictionaryLiteral { 77 | public init(dictionaryLiteral elements: (String, DictionaryValue)...) { 78 | self = .dictionary(Dictionary(uniqueKeysWithValues: elements)) 79 | } 80 | } 81 | 82 | extension DictionaryValue: ExpressibleByIntegerLiteral { 83 | public init(integerLiteral value: Int) { 84 | self = .number(value) 85 | } 86 | } 87 | 88 | extension DictionaryValue: ExpressibleByFloatLiteral { 89 | public init(floatLiteral value: Double) { 90 | self = .number(value) 91 | } 92 | } 93 | 94 | extension DictionaryValue: ExpressibleByStringLiteral { 95 | public init(stringLiteral value: String) { 96 | self = .string(value) 97 | } 98 | } 99 | 100 | func serialize(_ dictionary: [String: DictionaryValue]) -> PropertyList { 101 | var valueItems = [PropertyList]() 102 | valueItems.reserveCapacity(dictionary.count) 103 | 104 | for (key, value) in dictionary { 105 | var propertyList = value.propertyList 106 | propertyList["WFKey"] = [ 107 | "Value": ["string": key, "attachmentsByRange": [:]], 108 | "WFSerializationType": "WFTextTokenString", 109 | ] 110 | valueItems.append(propertyList) 111 | } 112 | 113 | return [ 114 | "Value": ["WFDictionaryFieldValueItems": valueItems], 115 | "WFSerializationType": "WFDictionaryFieldValue" 116 | ] 117 | } 118 | 119 | public func dictionary(_ value: [String: DictionaryValue]) -> ActionWithOutput { 120 | return Action(identifier: "is.workflow.actions.dictionary", parameters: ["WFItems": serialize(value)]) 121 | } 122 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/GetBatteryLevel.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func getBatteryLevel() -> ActionWithOutput { 4 | return Action(identifier: "is.workflow.actions.getbatterylevel", parameters: [:]) 5 | } 6 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/List.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct Item { 4 | let type: String 5 | let value: PropertyList 6 | var propertyList: PropertyList { 7 | return [ 8 | "WFItemType": type, 9 | "WFValue" : value 10 | ] 11 | } 12 | } 13 | 14 | public func list(_ items: [String]) -> ActionWithOutput { 15 | let items = items.map { itemString -> Any in 16 | let interpolatedText = withInterpolatedText(itemString) 17 | if interpolatedText is String { 18 | return itemString 19 | } 20 | return Item(type: "String", value: interpolatedText as! PropertyList).propertyList 21 | } 22 | return Action(identifier: "is.workflow.actions.list", parameters: ["WFItems": items]) 23 | } 24 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/Number.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Int: ActionContainer { 4 | public var actions: [Action] { 5 | return [Action(identifier: "is.workflow.actions.number", parameters: ["WFNumberActionNumber":self])] 6 | } 7 | } 8 | 9 | extension Float: ActionContainer { 10 | public var actions: [Action] { 11 | return [Action(identifier: "is.workflow.actions.number", parameters: ["WFNumberActionNumber":self])] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/Repeat.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class RepeatItem: Variable { 4 | init() { 5 | super.init(value: Attachment(type: "Variable", variableName: "Repeat Item")) 6 | } 7 | } 8 | 9 | public var repeatItem: RepeatItem { 10 | return RepeatItem() 11 | } 12 | 13 | public func repeatEach(_ actionContainer: ActionContainer) -> ActionContainer { 14 | let groupingIdentifier = UUID().uuidString 15 | var result = [Action]() 16 | let startRepeatParameters: PropertyList = [ 17 | "WFControlFlowMode": 0, 18 | "GroupingIdentifier": groupingIdentifier, 19 | ] 20 | let endRepeatParameters: PropertyList = [ 21 | "WFControlFlowMode": 2, 22 | "GroupingIdentifier": groupingIdentifier, 23 | ] 24 | result.append(Action(identifier: "is.workflow.actions.repeat.each", parameters: startRepeatParameters)) 25 | result.append(contentsOf: actionContainer.actions) 26 | result.append(Action(identifier: "is.workflow.actions.repeat.each", parameters: endRepeatParameters)) 27 | return result 28 | } 29 | 30 | public func repeatCount(_ actionContainer: ActionContainer, for count: Number) -> ActionContainer { 31 | let groupingIdentifier = UUID().uuidString 32 | var result = [Action]() 33 | let startRepeatParameters: PropertyList = [ 34 | "WFControlFlowMode": 0, 35 | "GroupingIdentifier": groupingIdentifier, 36 | "WFRepeatCount" : count 37 | ] 38 | let endRepeatParameters: PropertyList = [ 39 | "WFControlFlowMode": 2, 40 | "GroupingIdentifier": groupingIdentifier, 41 | ] 42 | result.append(Action(identifier: "is.workflow.actions.repeat.count", parameters: startRepeatParameters)) 43 | result.append(contentsOf: actionContainer.actions) 44 | result.append(Action(identifier: "is.workflow.actions.repeat.count", parameters: endRepeatParameters)) 45 | return result 46 | } 47 | 48 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/ReplaceText.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func replaceText(_ searchString: String, replaceWith replacement: String, caseSensitive: Bool = true, regularExpression: Bool = false) -> ActionWithOutput { 4 | return Action(identifier: "is.workflow.actions.text.replace", parameters: [ 5 | "WFReplaceTextFind": withInterpolatedText(searchString), 6 | "WFReplaceTextReplace": withInterpolatedText(replacement), 7 | "WFReplaceTextCaseSensitive": caseSensitive, 8 | "WFReplaceTextRegularExpression": regularExpression, 9 | ]) 10 | } 11 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/RunScene.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// This methods creates an Action that runs a HomeKit scene 4 | /// 5 | /// - Parameters: 6 | /// - home: The name of your home (The default name is "My Home") 7 | /// - name: The name of the scene you want to run 8 | public func runScene(for home: String, with name: String) -> ActionContainer { 9 | return Action(identifier: "is.workflow.actions.runscene", parameters: ["WFHomeName": home, "WFHomeSceneName": name]) 10 | } 11 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/SetLowPowerMode.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func setLowPowerMode(_ value: Bool = true) -> ActionContainer { 4 | return Action(identifier: "is.workflow.actions.lowpowermode.set", parameters: ["OnValue": value]) 5 | } 6 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/Share.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func share() -> ActionContainer { 4 | return Action(identifier: "is.workflow.actions.share", parameters: [:]) 5 | } 6 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/ShowResult.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func showResult(_ text: String) -> ActionContainer { 4 | return Action(identifier: "is.workflow.actions.showresult", parameters: ["Text": withInterpolatedText(text)]) 5 | } 6 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Actions/SplitText.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum TextSeparator { 4 | case everyLine 5 | case everyCharacter 6 | case spaces 7 | case custom(separator: String) 8 | case askWhenRun 9 | 10 | var parametersValue: PropertyList { 11 | let textSeparatorValue: Any? 12 | let additionalParameter: (String, Any)? 13 | switch self { 14 | case .everyCharacter: 15 | textSeparatorValue = "Every Caracter" 16 | additionalParameter = nil 17 | case .spaces: 18 | textSeparatorValue = "Spaces" 19 | additionalParameter = nil 20 | case .everyLine: 21 | textSeparatorValue = nil 22 | additionalParameter = nil 23 | case .custom(separator: let separator): 24 | textSeparatorValue = "Custom" 25 | additionalParameter = ("WFTextCustomSeparator", separator) 26 | case .askWhenRun: 27 | return [ 28 | "Value": ["Type": "Ask"] as PropertyList, 29 | "WFSerializationType": "WFTextTokenAttachment", 30 | ] as PropertyList 31 | } 32 | var result: PropertyList = [:] 33 | if let textSeparatorValue = textSeparatorValue { 34 | result["WFTextSeparator"] = textSeparatorValue 35 | } 36 | if let additionalParameter = additionalParameter { 37 | result[additionalParameter.0] = additionalParameter.1 38 | } 39 | 40 | return result 41 | } 42 | } 43 | 44 | public func splitText(_ separator: TextSeparator) -> ActionWithOutput { 45 | return Action(identifier: "is.workflow.actions.text.split", parameters: separator.parametersValue) 46 | } 47 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Aggrandizement.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum Aggrandizement { 4 | public enum DateFormatStyle { 5 | case none(TimeFormatStyle) 6 | case short(TimeFormatStyle) 7 | case medium(TimeFormatStyle) 8 | case long(TimeFormatStyle) 9 | case rfc2822 10 | case iso8601(includeTime: Bool) 11 | case relative(TimeFormatStyle) 12 | case custom(String) 13 | case howLongAgoUntil 14 | } 15 | 16 | public enum TimeFormatStyle { 17 | case none 18 | case short 19 | case medium 20 | case long 21 | 22 | var propertyListValue: Any { 23 | switch self { 24 | case .none: return "None" 25 | case .short: return "Short" 26 | case .medium: return "Medium" 27 | case .long: return "Long" 28 | } 29 | } 30 | } 31 | 32 | public enum CoercionItemClass { 33 | case anything 34 | case appStoreApp 35 | case article 36 | case boolean 37 | case contact 38 | case date 39 | case dictionary 40 | case emailAddress 41 | case file 42 | case image 43 | case iTunesMedia 44 | case iTunesProduct 45 | case location 46 | case mapsLink 47 | case media 48 | case number 49 | case pdf 50 | case phoneNumber 51 | case photoMedia 52 | case place 53 | case richText 54 | case safariWebPage 55 | case text 56 | case url 57 | case vCard 58 | 59 | var propertyListValue: String? { 60 | switch self { 61 | case .anything: return "WFContentItem" 62 | case .appStoreApp: return "WFAppStoreAppContentItem" 63 | case .article: return "WFArticleContentItem" 64 | case .boolean: return "WFBooleanContentItem" 65 | case .contact: return "WFContactContentItem" 66 | case .date: return "WFDateContentItem" 67 | case .dictionary: return "WFDictionaryContentItem" 68 | case .emailAddress: return "WFEmailAddressContentItem" 69 | case .file: return "WFGenericFileContentItem" 70 | case .image: return "WFImageContentItem" 71 | case .iTunesMedia: return "WFMPMediaContentItem" 72 | case .iTunesProduct: return "WFiTunesProductContentItem" 73 | case .location: return "WFLocationContentItem" 74 | case .mapsLink: return "WFDCMapsLinkContentItem" 75 | case .media: return "WFAVAssetContentItem" 76 | case .number: return "WFNumberContentItem" 77 | case .pdf: return "WFPDFContentItem" 78 | case .phoneNumber: return "WFPhoneNumberContentItem" 79 | case .photoMedia: return "WFPhotoMediaContentItem" 80 | case .place: return "WFMKMapItemContentItem" 81 | case .richText: return "WFRichTextContentItem" 82 | case .safariWebPage: return "WFSafariWebPageContentItem" 83 | case .text: return nil 84 | case .url: return "WFURLContentItem" 85 | case .vCard: return "WFVCardContentItem" 86 | } 87 | } 88 | } 89 | 90 | public enum PropertyName { 91 | case fileSize 92 | case fileExtension 93 | case name 94 | case custom(String) 95 | 96 | var propertyListValue: Any { 97 | switch self { 98 | case .fileSize: return "File Size" 99 | case .fileExtension: return "File Extension" 100 | case .name: return "Name" 101 | case .custom(let propertyName): return propertyName 102 | } 103 | } 104 | } 105 | 106 | public enum PropertyUserInfo { 107 | case fileSize 108 | case fileExtension 109 | case number(Number) 110 | 111 | var propertyListValue: Any { 112 | switch self { 113 | case .fileSize: return "WFFileSizeProperty" 114 | case .fileExtension: return "WFFileExtensionProperty" 115 | case .number(let number): return number 116 | } 117 | } 118 | } 119 | 120 | case coercion(class: CoercionItemClass) 121 | case dateFormat(DateFormatStyle) 122 | case dictionaryValue(key: String?) 123 | case property(name: PropertyName, userInfo: PropertyUserInfo) 124 | 125 | var propertyList: PropertyList { 126 | switch self { 127 | case .coercion(let coercionClass): 128 | var result: PropertyList = ["Type": "WFCoercionVariableAggrandizement"] 129 | result["CoercionItemClass"] = coercionClass.propertyListValue 130 | return result 131 | case .dateFormat(let format): 132 | var result: PropertyList = ["Type": "WFDateFormatVariableAggrandizement"] 133 | 134 | switch format { 135 | case .none(let timeFormatStyle): 136 | result["WFDateFormatStyle"] = "None" 137 | result["WFTimeFormatStyle"] = timeFormatStyle.propertyListValue 138 | case .short(let timeFormatStyle): 139 | result["WFDateFormatStyle"] = "Short" 140 | result["WFTimeFormatStyle"] = timeFormatStyle.propertyListValue 141 | case .medium(let timeFormatStyle): 142 | result["WFDateFormatStyle"] = "Medium" 143 | result["WFTimeFormatStyle"] = timeFormatStyle.propertyListValue 144 | case .long(let timeFormatStyle): 145 | result["WFDateFormatStyle"] = "Long" 146 | result["WFTimeFormatStyle"] = timeFormatStyle.propertyListValue 147 | case .rfc2822: 148 | result["WFDateFormatStyle"] = "RFC 2822" 149 | case .iso8601(let includeTime): 150 | result["WFDateFormatStyle"] = "ISO 8601" 151 | result["WFISO8601IncludeTime"] = includeTime 152 | case .relative(let timeFormatStyle): 153 | result["WFDateFormatStyle"] = "Relative" 154 | result["WFTimeFormatStyle"] = timeFormatStyle.propertyListValue 155 | result["WFRelativeDateFormatStyle"] = "Short" 156 | case .custom(let dateFormat): 157 | result["WFDateFormatStyle"] = "Custom" 158 | result["WFDateFormat"] = dateFormat 159 | case .howLongAgoUntil: 160 | result["WFDateFormatStyle"] = "Relative" 161 | } 162 | 163 | return result 164 | case .dictionaryValue(let key): 165 | var result: PropertyList = ["Type": "WFDictionaryValueVariableAggrandizement"] 166 | result["DictionaryKey"] = key 167 | return result 168 | case .property(let name, let userInfo): 169 | return [ 170 | "Type": "WFPropertyVariableAggrandizement", 171 | "PropertyName": name.propertyListValue, 172 | "PropertyUserInfo": userInfo.propertyListValue, 173 | ] 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Attachment.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct Attachment { 4 | public var type: String 5 | public var aggrandizements: [Aggrandizement]? 6 | public var outputName: String? 7 | public var outputUUID: UUID? 8 | public var variableName: String? 9 | 10 | public init(type: String, aggrandizements: [Aggrandizement]? = nil, outputName: String? = nil, outputUUID: UUID? = nil, variableName: String? = nil) { 11 | self.type = type 12 | self.aggrandizements = aggrandizements 13 | self.outputName = outputName 14 | self.outputUUID = outputUUID 15 | self.variableName = variableName 16 | } 17 | 18 | var propertyList: PropertyList { 19 | var result: PropertyList = ["Type": type] 20 | result["Aggrandizements"] = aggrandizements?.map { $0.propertyList } 21 | result["OutputUUID"] = outputUUID?.uuidString 22 | result["OutputName"] = outputName 23 | result["VariableName"] = variableName 24 | return result 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/BaseTypes.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public typealias PropertyList = [String: Any] 4 | 5 | public protocol Number {} 6 | extension Int8: Number {} 7 | extension Int16: Number {} 8 | extension Int32: Number {} 9 | extension Int64: Number {} 10 | extension Int: Number {} 11 | extension UInt8: Number {} 12 | extension UInt16: Number {} 13 | extension UInt32: Number {} 14 | extension UInt64: Number {} 15 | extension UInt: Number {} 16 | extension Double: Number {} 17 | extension Float: Number {} 18 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/BuildShortcut.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func buildShortcut(_ actionContainer: ActionContainer) -> PropertyList { 4 | let actions = actionContainer.actions.map { $0.propertyList } 5 | return [ 6 | "WFWorkflowClientVersion": "754", 7 | "WFWorkflowClientRelease": "2.1.2", 8 | "WFWorkflowMinimumClientVersion": 411, 9 | "WFWorkflowTypes": ["WatchKit", "NCWidget"] as [String], 10 | "WFWorkflowIcon": [ 11 | "WFWorkflowIconStartColor": 4282601983, 12 | "WFWorkflowIconImageData": Data(), 13 | "WFWorkflowIconGlyphNumber": 59511, 14 | ] as PropertyList, 15 | "WFWorkflowInputContentItemClasses": [ 16 | "WFAppStoreAppContentItem", 17 | "WFArticleContentItem", 18 | "WFContactContentItem", 19 | "WFDateContentItem", 20 | "WFEmailAddressContentItem", 21 | "WFGenericFileContentItem", 22 | "WFImageContentItem", 23 | "WFiTunesProductContentItem", 24 | "WFLocationContentItem", 25 | "WFDCMapsLinkContentItem", 26 | "WFAVAssetContentItem", 27 | "WFPDFContentItem", 28 | "WFPhoneNumberContentItem", 29 | "WFRichTextContentItem", 30 | "WFSafariWebPageContentItem", 31 | "WFStringContentItem", 32 | "WFURLContentItem", 33 | ] as [String], 34 | "WFWorkflowActions": actions 35 | ] as PropertyList 36 | } 37 | 38 | public func exportShortcut(_ actionContainer: ActionContainer) -> Data { 39 | return try! PropertyListSerialization.data(fromPropertyList: buildShortcut(actionContainer), format: .binary, options: 0) 40 | } 41 | 42 | #if canImport(PlaygroundSupport) 43 | 44 | import PlaygroundSupport 45 | 46 | public func shareShortcut(_ shortcut: PropertyList, named name: String) { 47 | let data = try! PropertyListSerialization.data(fromPropertyList: shortcut, format: .binary, options: 0) 48 | if let remoteView = PlaygroundPage.current.liveView as? PlaygroundRemoteLiveViewProxy { 49 | remoteView.send(.dictionary(["name": .string(name), "data": .data(data)])) 50 | } 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/InterpolatedText.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | func withInterpolatedText(_ string: String) -> Any { 4 | var result = string 5 | var attachments = [String: Any]() 6 | 7 | let objectReplacementCharacter = "\u{fffc}" 8 | let replacementCharacter = "\u{fffd}" 9 | 10 | var rangeStart = result.startIndex 11 | while let orcRange = result.range(of: objectReplacementCharacter, range: rangeStart ..< result.endIndex) { 12 | if let rcRange = result.range(of: replacementCharacter, range: orcRange.upperBound ..< result.endIndex) { 13 | let data = Data(result[orcRange.upperBound ..< rcRange.lowerBound].utf8) 14 | let jsonObject = try! JSONSerialization.jsonObject(with: data) 15 | attachments[NSStringFromRange(NSRange(orcRange, in: result))] = jsonObject 16 | result.removeSubrange(orcRange.upperBound ..< rcRange.upperBound) 17 | } 18 | 19 | rangeStart = orcRange.upperBound 20 | } 21 | 22 | guard !attachments.isEmpty else { 23 | return string 24 | } 25 | 26 | return [ 27 | "WFSerializationType": "WFTextTokenString", 28 | "Value": ["string": result, "attachmentsByRange": attachments], 29 | ] as PropertyList 30 | } 31 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/UI/ShortcutShareViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | #if !Xcode 4 | import PlaygroundSupport 5 | #endif 6 | 7 | public class ShortcutShareViewController: UIViewController, PlaygroundLiveViewMessageHandler, PlaygroundLiveViewSafeAreaContainer { 8 | var button: UIButton? 9 | var shortcutURL: URL? { 10 | didSet { 11 | button?.isEnabled = shortcutURL != nil 12 | } 13 | } 14 | 15 | // MARK: - Actions 16 | 17 | @objc func share(_ sender: UIView) { 18 | guard let shortcutURL = shortcutURL else { 19 | return 20 | } 21 | 22 | let activityViewController = UIActivityViewController(activityItems: [shortcutURL], applicationActivities: nil) 23 | if let popover = activityViewController.popoverPresentationController { 24 | popover.sourceRect = sender.bounds 25 | popover.sourceView = sender 26 | } 27 | present(activityViewController, animated: true) 28 | } 29 | 30 | // MARK: - Message Handling 31 | 32 | public func receive(_ message: PlaygroundValue) { 33 | guard case .dictionary(let dictionary) = message, 34 | case PlaygroundValue.string(let name)? = dictionary["name"], 35 | case PlaygroundValue.data(let data)? = dictionary["data"] 36 | else { 37 | return 38 | } 39 | 40 | guard let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { 41 | return 42 | } 43 | 44 | let fileURL = documentDirectory.appendingPathComponent(name).appendingPathExtension("shortcut") 45 | try! data.write(to: fileURL) 46 | self.shortcutURL = fileURL 47 | } 48 | 49 | // MARK: - View Life Cycle 50 | 51 | public override func viewDidLoad() { 52 | super.viewDidLoad() 53 | 54 | let button = UIButton(type: .system) 55 | button.isEnabled = false 56 | button.titleLabel?.adjustsFontForContentSizeCategory = true 57 | button.titleLabel?.font = .preferredFont(forTextStyle: .headline) 58 | button.translatesAutoresizingMaskIntoConstraints = false 59 | button.addTarget(self, action: #selector(share), for: .touchUpInside) 60 | button.setTitle("Share", for: .normal) 61 | view.addSubview(button) 62 | self.button = button 63 | 64 | NSLayoutConstraint.activate([ 65 | button.centerXAnchor.constraint(equalTo: liveViewSafeAreaGuide.centerXAnchor), 66 | button.bottomAnchor.constraint(equalTo: liveViewSafeAreaGuide.bottomAnchor), 67 | ]) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /ShortcutsSwift.playgroundbook/Contents/Sources/Variable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class Variable: CustomStringConvertible { 4 | public var value: Attachment 5 | 6 | public init(value: Attachment) { 7 | self.value = value 8 | } 9 | 10 | var propertyList: PropertyList { 11 | return [ 12 | "WFSerializationType": "WFTextTokenAttachment", 13 | "Value": value.propertyList 14 | ] 15 | } 16 | 17 | public func with(dateFormat: Aggrandizement.DateFormatStyle) -> Variable { 18 | let result = Variable(value: value) 19 | result.value.aggrandizements = [.coercion(class: .date), .dateFormat(dateFormat)] 20 | return result 21 | } 22 | 23 | public func with(propertyName: Aggrandizement.PropertyName, userInfo: Aggrandizement.PropertyUserInfo) -> Variable { 24 | let result = Variable(value: value) 25 | result.value.aggrandizements = [.property(name: propertyName, userInfo: userInfo)] 26 | return result 27 | } 28 | 29 | public func with(valueForKey key: String?) -> Variable { 30 | let result = Variable(value: value) 31 | result.value.aggrandizements = [.coercion(class: .dictionary), .dictionaryValue(key: key)] 32 | return result 33 | } 34 | 35 | public func with(type: Aggrandizement.CoercionItemClass) -> Variable { 36 | let result = Variable(value: value) 37 | result.value.aggrandizements = [.coercion(class: type)] 38 | return result 39 | } 40 | 41 | public final var description: String { 42 | let data = try! JSONSerialization.data(withJSONObject: value.propertyList) 43 | return "\u{fffc}\(String(decoding: data, as: UTF8.self))\u{fffd}" 44 | } 45 | } 46 | 47 | public class ActionOutputVariable: Variable { 48 | public init(name: String? = nil) { 49 | super.init(value: Attachment(type: "ActionOutput", outputName: name, outputUUID: UUID())) 50 | } 51 | } 52 | 53 | public func actionOutput(name: String? = nil) -> ActionOutputVariable { 54 | return ActionOutputVariable(name: name) 55 | } 56 | 57 | public func askWhenRun() -> Variable { 58 | return Variable(value: Attachment(type: "Ask")) 59 | } 60 | 61 | public func clipboard() -> Variable { 62 | return Variable(value: Attachment(type: "Clipboard")) 63 | } 64 | 65 | public func currentDate() -> Variable { 66 | return Variable(value: Attachment(type: "CurrentDate")) 67 | } 68 | 69 | public func shortcutInput() -> Variable { 70 | return Variable(value: Attachment(type: "ExtensionInput")) 71 | } 72 | -------------------------------------------------------------------------------- /ShortcutsSwift.xcodeproj/ShortcutsSwift-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /ShortcutsSwift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5502001621D10C9200CE7544 /* ShortcutsSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502001521D10C9200CE7544 /* ShortcutsSwiftTests.swift */; }; 11 | 5502001821D10C9200CE7544 /* ShortcutsSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5502FF8621D0F06500CE7544 /* ShortcutsSwift.framework */; }; 12 | 5502FFD721D0F1A400CE7544 /* ShortcutShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFC221D0F1A300CE7544 /* ShortcutShareViewController.swift */; }; 13 | 5502FFD821D0F1A400CE7544 /* ActionOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFC321D0F1A300CE7544 /* ActionOutput.swift */; }; 14 | 5502FFD921D0F1A400CE7544 /* InterpolatedText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFC421D0F1A300CE7544 /* InterpolatedText.swift */; }; 15 | 5502FFDA21D0F1A400CE7544 /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFC521D0F1A300CE7544 /* Attachment.swift */; }; 16 | 5502FFDC21D0F1A400CE7544 /* BaseTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFC721D0F1A300CE7544 /* BaseTypes.swift */; }; 17 | 5502FFDD21D0F1A400CE7544 /* CopyToClipboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFC921D0F1A300CE7544 /* CopyToClipboard.swift */; }; 18 | 5502FFDE21D0F1A400CE7544 /* AskForInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFCA21D0F1A300CE7544 /* AskForInput.swift */; }; 19 | 5502FFDF21D0F1A400CE7544 /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFCB21D0F1A400CE7544 /* Comment.swift */; }; 20 | 5502FFE021D0F1A400CE7544 /* ReplaceText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFCC21D0F1A400CE7544 /* ReplaceText.swift */; }; 21 | 5502FFE121D0F1A400CE7544 /* Conditional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFCD21D0F1A400CE7544 /* Conditional.swift */; }; 22 | 5502FFE221D0F1A400CE7544 /* ChangeCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFCE21D0F1A400CE7544 /* ChangeCase.swift */; }; 23 | 5502FFE321D0F1A400CE7544 /* ChooseFromMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFCF21D0F1A400CE7544 /* ChooseFromMenu.swift */; }; 24 | 5502FFE421D0F1A400CE7544 /* Share.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFD021D0F1A400CE7544 /* Share.swift */; }; 25 | 5502FFE521D0F1A400CE7544 /* ShowResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFD121D0F1A400CE7544 /* ShowResult.swift */; }; 26 | 5502FFE621D0F1A400CE7544 /* SetLowPowerMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFD221D0F1A400CE7544 /* SetLowPowerMode.swift */; }; 27 | 5502FFE721D0F1A400CE7544 /* GetBatteryLevel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFD321D0F1A400CE7544 /* GetBatteryLevel.swift */; }; 28 | 5502FFE821D0F1A400CE7544 /* Variable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFD421D0F1A400CE7544 /* Variable.swift */; }; 29 | 5502FFE921D0F1A400CE7544 /* BuildShortcut.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFD521D0F1A400CE7544 /* BuildShortcut.swift */; }; 30 | 5502FFEA21D0F1A400CE7544 /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFD621D0F1A400CE7544 /* Action.swift */; }; 31 | 5502FFEC21D0F29700CE7544 /* PlaygroundSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5502FFEB21D0F29700CE7544 /* PlaygroundSupport.swift */; }; 32 | 5502FFF321D0F58400CE7544 /* ShortcutsSwift.playgroundbook in Resources */ = {isa = PBXBuildFile; fileRef = 5502FFF221D0F58400CE7544 /* ShortcutsSwift.playgroundbook */; }; 33 | 83F8639621D1454600925583 /* Aggrandizement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F8639521D1454600925583 /* Aggrandizement.swift */; }; 34 | 83F8639821D15F7E00925583 /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F8639721D15F7E00925583 /* Dictionary.swift */; }; 35 | 9826044721D414B2001E3B31 /* Number.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9826044621D414B2001E3B31 /* Number.swift */; }; 36 | 98D33C2721D3D29100824660 /* RunScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D33C2621D3D29100824660 /* RunScene.swift */; }; 37 | 98D33C2921D3DA0A00824660 /* SplitText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D33C2821D3DA0A00824660 /* SplitText.swift */; }; 38 | 98D33C2B21D3E34100824660 /* Repeat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D33C2A21D3E34100824660 /* Repeat.swift */; }; 39 | 98D33C3021D3EFF100824660 /* Calculate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D33C2F21D3EFF100824660 /* Calculate.swift */; }; 40 | 98D33C3421D4067C00824660 /* List.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98D33C3321D4067C00824660 /* List.swift */; }; 41 | FBDA8D4321DCCA9E00303374 /* AggrandizementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBDA8D4221DCCA9E00303374 /* AggrandizementTests.swift */; }; 42 | /* End PBXBuildFile section */ 43 | 44 | /* Begin PBXContainerItemProxy section */ 45 | 5502001921D10C9200CE7544 /* PBXContainerItemProxy */ = { 46 | isa = PBXContainerItemProxy; 47 | containerPortal = 5502FF7D21D0F06500CE7544 /* Project object */; 48 | proxyType = 1; 49 | remoteGlobalIDString = 5502FF8521D0F06500CE7544; 50 | remoteInfo = ShortcutsSwift; 51 | }; 52 | /* End PBXContainerItemProxy section */ 53 | 54 | /* Begin PBXFileReference section */ 55 | 5502001321D10C9200CE7544 /* ShortcutsSwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ShortcutsSwiftTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | 5502001521D10C9200CE7544 /* ShortcutsSwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsSwiftTests.swift; sourceTree = ""; }; 57 | 5502001721D10C9200CE7544 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | 5502FF8621D0F06500CE7544 /* ShortcutsSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ShortcutsSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | 5502FFC221D0F1A300CE7544 /* ShortcutShareViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutShareViewController.swift; sourceTree = ""; }; 60 | 5502FFC321D0F1A300CE7544 /* ActionOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionOutput.swift; sourceTree = ""; }; 61 | 5502FFC421D0F1A300CE7544 /* InterpolatedText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InterpolatedText.swift; sourceTree = ""; }; 62 | 5502FFC521D0F1A300CE7544 /* Attachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Attachment.swift; sourceTree = ""; }; 63 | 5502FFC721D0F1A300CE7544 /* BaseTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTypes.swift; sourceTree = ""; }; 64 | 5502FFC921D0F1A300CE7544 /* CopyToClipboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CopyToClipboard.swift; sourceTree = ""; }; 65 | 5502FFCA21D0F1A300CE7544 /* AskForInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AskForInput.swift; sourceTree = ""; }; 66 | 5502FFCB21D0F1A400CE7544 /* Comment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Comment.swift; sourceTree = ""; }; 67 | 5502FFCC21D0F1A400CE7544 /* ReplaceText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplaceText.swift; sourceTree = ""; }; 68 | 5502FFCD21D0F1A400CE7544 /* Conditional.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Conditional.swift; sourceTree = ""; }; 69 | 5502FFCE21D0F1A400CE7544 /* ChangeCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeCase.swift; sourceTree = ""; }; 70 | 5502FFCF21D0F1A400CE7544 /* ChooseFromMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChooseFromMenu.swift; sourceTree = ""; }; 71 | 5502FFD021D0F1A400CE7544 /* Share.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Share.swift; sourceTree = ""; }; 72 | 5502FFD121D0F1A400CE7544 /* ShowResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShowResult.swift; sourceTree = ""; }; 73 | 5502FFD221D0F1A400CE7544 /* SetLowPowerMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetLowPowerMode.swift; sourceTree = ""; }; 74 | 5502FFD321D0F1A400CE7544 /* GetBatteryLevel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetBatteryLevel.swift; sourceTree = ""; }; 75 | 5502FFD421D0F1A400CE7544 /* Variable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Variable.swift; sourceTree = ""; }; 76 | 5502FFD521D0F1A400CE7544 /* BuildShortcut.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BuildShortcut.swift; sourceTree = ""; }; 77 | 5502FFD621D0F1A400CE7544 /* Action.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Action.swift; sourceTree = ""; }; 78 | 5502FFEB21D0F29700CE7544 /* PlaygroundSupport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaygroundSupport.swift; sourceTree = ""; }; 79 | 5502FFF221D0F58400CE7544 /* ShortcutsSwift.playgroundbook */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = ShortcutsSwift.playgroundbook; sourceTree = ""; }; 80 | 83F8639521D1454600925583 /* Aggrandizement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Aggrandizement.swift; sourceTree = ""; }; 81 | 83F8639721D15F7E00925583 /* Dictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dictionary.swift; sourceTree = ""; }; 82 | 9826044621D414B2001E3B31 /* Number.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Number.swift; sourceTree = ""; }; 83 | 98D33C2621D3D29100824660 /* RunScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunScene.swift; sourceTree = ""; }; 84 | 98D33C2821D3DA0A00824660 /* SplitText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplitText.swift; sourceTree = ""; }; 85 | 98D33C2A21D3E34100824660 /* Repeat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Repeat.swift; sourceTree = ""; }; 86 | 98D33C2F21D3EFF100824660 /* Calculate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Calculate.swift; sourceTree = ""; }; 87 | 98D33C3321D4067C00824660 /* List.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = List.swift; sourceTree = ""; }; 88 | FBDA8D4221DCCA9E00303374 /* AggrandizementTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AggrandizementTests.swift; sourceTree = ""; }; 89 | /* End PBXFileReference section */ 90 | 91 | /* Begin PBXFrameworksBuildPhase section */ 92 | 5502001021D10C9200CE7544 /* Frameworks */ = { 93 | isa = PBXFrameworksBuildPhase; 94 | buildActionMask = 2147483647; 95 | files = ( 96 | 5502001821D10C9200CE7544 /* ShortcutsSwift.framework in Frameworks */, 97 | ); 98 | runOnlyForDeploymentPostprocessing = 0; 99 | }; 100 | 5502FF8321D0F06500CE7544 /* Frameworks */ = { 101 | isa = PBXFrameworksBuildPhase; 102 | buildActionMask = 2147483647; 103 | files = ( 104 | ); 105 | runOnlyForDeploymentPostprocessing = 0; 106 | }; 107 | /* End PBXFrameworksBuildPhase section */ 108 | 109 | /* Begin PBXGroup section */ 110 | 5502001421D10C9200CE7544 /* Tests */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 5502001521D10C9200CE7544 /* ShortcutsSwiftTests.swift */, 114 | FBDA8D4221DCCA9E00303374 /* AggrandizementTests.swift */, 115 | 5502001721D10C9200CE7544 /* Info.plist */, 116 | ); 117 | path = Tests; 118 | sourceTree = ""; 119 | }; 120 | 5502FF7C21D0F06500CE7544 = { 121 | isa = PBXGroup; 122 | children = ( 123 | 5502FFF221D0F58400CE7544 /* ShortcutsSwift.playgroundbook */, 124 | 5502FFED21D0F2AB00CE7544 /* Helpers */, 125 | 5502FFC021D0F1A300CE7544 /* Sources */, 126 | 5502001421D10C9200CE7544 /* Tests */, 127 | 5502FF8721D0F06500CE7544 /* Products */, 128 | ); 129 | sourceTree = ""; 130 | }; 131 | 5502FF8721D0F06500CE7544 /* Products */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 5502FF8621D0F06500CE7544 /* ShortcutsSwift.framework */, 135 | 5502001321D10C9200CE7544 /* ShortcutsSwiftTests.xctest */, 136 | ); 137 | name = Products; 138 | sourceTree = ""; 139 | }; 140 | 5502FFC021D0F1A300CE7544 /* Sources */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | 5502FFD621D0F1A400CE7544 /* Action.swift */, 144 | 5502FFC321D0F1A300CE7544 /* ActionOutput.swift */, 145 | 5502FFC821D0F1A300CE7544 /* Actions */, 146 | 83F8639521D1454600925583 /* Aggrandizement.swift */, 147 | 5502FFC521D0F1A300CE7544 /* Attachment.swift */, 148 | 5502FFC721D0F1A300CE7544 /* BaseTypes.swift */, 149 | 5502FFD521D0F1A400CE7544 /* BuildShortcut.swift */, 150 | 5502FFC421D0F1A300CE7544 /* InterpolatedText.swift */, 151 | 5502FFC121D0F1A300CE7544 /* UI */, 152 | 5502FFD421D0F1A400CE7544 /* Variable.swift */, 153 | ); 154 | name = Sources; 155 | path = ShortcutsSwift.playgroundbook/Contents/Sources; 156 | sourceTree = ""; 157 | }; 158 | 5502FFC121D0F1A300CE7544 /* UI */ = { 159 | isa = PBXGroup; 160 | children = ( 161 | 5502FFC221D0F1A300CE7544 /* ShortcutShareViewController.swift */, 162 | ); 163 | path = UI; 164 | sourceTree = ""; 165 | }; 166 | 5502FFC821D0F1A300CE7544 /* Actions */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | 5502FFCA21D0F1A300CE7544 /* AskForInput.swift */, 170 | 98D33C2F21D3EFF100824660 /* Calculate.swift */, 171 | 5502FFCE21D0F1A400CE7544 /* ChangeCase.swift */, 172 | 5502FFCF21D0F1A400CE7544 /* ChooseFromMenu.swift */, 173 | 5502FFCB21D0F1A400CE7544 /* Comment.swift */, 174 | 5502FFCD21D0F1A400CE7544 /* Conditional.swift */, 175 | 5502FFC921D0F1A300CE7544 /* CopyToClipboard.swift */, 176 | 83F8639721D15F7E00925583 /* Dictionary.swift */, 177 | 5502FFD321D0F1A400CE7544 /* GetBatteryLevel.swift */, 178 | 98D33C3321D4067C00824660 /* List.swift */, 179 | 9826044621D414B2001E3B31 /* Number.swift */, 180 | 98D33C2A21D3E34100824660 /* Repeat.swift */, 181 | 5502FFCC21D0F1A400CE7544 /* ReplaceText.swift */, 182 | 98D33C2621D3D29100824660 /* RunScene.swift */, 183 | 5502FFD221D0F1A400CE7544 /* SetLowPowerMode.swift */, 184 | 5502FFD021D0F1A400CE7544 /* Share.swift */, 185 | 5502FFD121D0F1A400CE7544 /* ShowResult.swift */, 186 | 98D33C2821D3DA0A00824660 /* SplitText.swift */, 187 | ); 188 | path = Actions; 189 | sourceTree = ""; 190 | }; 191 | 5502FFED21D0F2AB00CE7544 /* Helpers */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | 5502FFEB21D0F29700CE7544 /* PlaygroundSupport.swift */, 195 | ); 196 | path = Helpers; 197 | sourceTree = ""; 198 | }; 199 | /* End PBXGroup section */ 200 | 201 | /* Begin PBXHeadersBuildPhase section */ 202 | 5502FF8121D0F06500CE7544 /* Headers */ = { 203 | isa = PBXHeadersBuildPhase; 204 | buildActionMask = 2147483647; 205 | files = ( 206 | ); 207 | runOnlyForDeploymentPostprocessing = 0; 208 | }; 209 | /* End PBXHeadersBuildPhase section */ 210 | 211 | /* Begin PBXNativeTarget section */ 212 | 5502001221D10C9200CE7544 /* ShortcutsSwiftTests */ = { 213 | isa = PBXNativeTarget; 214 | buildConfigurationList = 5502001D21D10C9A00CE7544 /* Build configuration list for PBXNativeTarget "ShortcutsSwiftTests" */; 215 | buildPhases = ( 216 | 5502000F21D10C9200CE7544 /* Sources */, 217 | 5502001021D10C9200CE7544 /* Frameworks */, 218 | 5502001121D10C9200CE7544 /* Resources */, 219 | ); 220 | buildRules = ( 221 | ); 222 | dependencies = ( 223 | 5502001A21D10C9200CE7544 /* PBXTargetDependency */, 224 | ); 225 | name = ShortcutsSwiftTests; 226 | productName = ShortcutsSwiftTests; 227 | productReference = 5502001321D10C9200CE7544 /* ShortcutsSwiftTests.xctest */; 228 | productType = "com.apple.product-type.bundle.unit-test"; 229 | }; 230 | 5502FF8521D0F06500CE7544 /* ShortcutsSwift */ = { 231 | isa = PBXNativeTarget; 232 | buildConfigurationList = 5502FF8E21D0F06500CE7544 /* Build configuration list for PBXNativeTarget "ShortcutsSwift" */; 233 | buildPhases = ( 234 | 5502FF8121D0F06500CE7544 /* Headers */, 235 | 5502FF8221D0F06500CE7544 /* Sources */, 236 | 5502FF8321D0F06500CE7544 /* Frameworks */, 237 | 5502FF8421D0F06500CE7544 /* Resources */, 238 | ); 239 | buildRules = ( 240 | ); 241 | dependencies = ( 242 | ); 243 | name = ShortcutsSwift; 244 | productName = ShortcutsSwift; 245 | productReference = 5502FF8621D0F06500CE7544 /* ShortcutsSwift.framework */; 246 | productType = "com.apple.product-type.framework"; 247 | }; 248 | /* End PBXNativeTarget section */ 249 | 250 | /* Begin PBXProject section */ 251 | 5502FF7D21D0F06500CE7544 /* Project object */ = { 252 | isa = PBXProject; 253 | attributes = { 254 | LastSwiftUpdateCheck = 1010; 255 | LastUpgradeCheck = 1010; 256 | ORGANIZATIONNAME = "Pandamonia LLC"; 257 | TargetAttributes = { 258 | 5502001221D10C9200CE7544 = { 259 | CreatedOnToolsVersion = 10.1; 260 | }; 261 | 5502FF8521D0F06500CE7544 = { 262 | CreatedOnToolsVersion = 10.1; 263 | }; 264 | }; 265 | }; 266 | buildConfigurationList = 5502FF8021D0F06500CE7544 /* Build configuration list for PBXProject "ShortcutsSwift" */; 267 | compatibilityVersion = "Xcode 9.3"; 268 | developmentRegion = en; 269 | hasScannedForEncodings = 0; 270 | knownRegions = ( 271 | en, 272 | ); 273 | mainGroup = 5502FF7C21D0F06500CE7544; 274 | productRefGroup = 5502FF8721D0F06500CE7544 /* Products */; 275 | projectDirPath = ""; 276 | projectRoot = ""; 277 | targets = ( 278 | 5502FF8521D0F06500CE7544 /* ShortcutsSwift */, 279 | 5502001221D10C9200CE7544 /* ShortcutsSwiftTests */, 280 | ); 281 | }; 282 | /* End PBXProject section */ 283 | 284 | /* Begin PBXResourcesBuildPhase section */ 285 | 5502001121D10C9200CE7544 /* Resources */ = { 286 | isa = PBXResourcesBuildPhase; 287 | buildActionMask = 2147483647; 288 | files = ( 289 | ); 290 | runOnlyForDeploymentPostprocessing = 0; 291 | }; 292 | 5502FF8421D0F06500CE7544 /* Resources */ = { 293 | isa = PBXResourcesBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | 5502FFF321D0F58400CE7544 /* ShortcutsSwift.playgroundbook in Resources */, 297 | ); 298 | runOnlyForDeploymentPostprocessing = 0; 299 | }; 300 | /* End PBXResourcesBuildPhase section */ 301 | 302 | /* Begin PBXSourcesBuildPhase section */ 303 | 5502000F21D10C9200CE7544 /* Sources */ = { 304 | isa = PBXSourcesBuildPhase; 305 | buildActionMask = 2147483647; 306 | files = ( 307 | 5502001621D10C9200CE7544 /* ShortcutsSwiftTests.swift in Sources */, 308 | FBDA8D4321DCCA9E00303374 /* AggrandizementTests.swift in Sources */, 309 | ); 310 | runOnlyForDeploymentPostprocessing = 0; 311 | }; 312 | 5502FF8221D0F06500CE7544 /* Sources */ = { 313 | isa = PBXSourcesBuildPhase; 314 | buildActionMask = 2147483647; 315 | files = ( 316 | 5502FFE621D0F1A400CE7544 /* SetLowPowerMode.swift in Sources */, 317 | 98D33C2721D3D29100824660 /* RunScene.swift in Sources */, 318 | 5502FFE821D0F1A400CE7544 /* Variable.swift in Sources */, 319 | 5502FFDA21D0F1A400CE7544 /* Attachment.swift in Sources */, 320 | 98D33C3021D3EFF100824660 /* Calculate.swift in Sources */, 321 | 83F8639621D1454600925583 /* Aggrandizement.swift in Sources */, 322 | 5502FFE021D0F1A400CE7544 /* ReplaceText.swift in Sources */, 323 | 9826044721D414B2001E3B31 /* Number.swift in Sources */, 324 | 5502FFE121D0F1A400CE7544 /* Conditional.swift in Sources */, 325 | 5502FFD921D0F1A400CE7544 /* InterpolatedText.swift in Sources */, 326 | 5502FFE721D0F1A400CE7544 /* GetBatteryLevel.swift in Sources */, 327 | 5502FFDE21D0F1A400CE7544 /* AskForInput.swift in Sources */, 328 | 5502FFE221D0F1A400CE7544 /* ChangeCase.swift in Sources */, 329 | 5502FFE921D0F1A400CE7544 /* BuildShortcut.swift in Sources */, 330 | 5502FFDC21D0F1A400CE7544 /* BaseTypes.swift in Sources */, 331 | 5502FFD821D0F1A400CE7544 /* ActionOutput.swift in Sources */, 332 | 5502FFEC21D0F29700CE7544 /* PlaygroundSupport.swift in Sources */, 333 | 5502FFEA21D0F1A400CE7544 /* Action.swift in Sources */, 334 | 83F8639821D15F7E00925583 /* Dictionary.swift in Sources */, 335 | 98D33C3421D4067C00824660 /* List.swift in Sources */, 336 | 98D33C2B21D3E34100824660 /* Repeat.swift in Sources */, 337 | 5502FFE421D0F1A400CE7544 /* Share.swift in Sources */, 338 | 98D33C2921D3DA0A00824660 /* SplitText.swift in Sources */, 339 | 5502FFDD21D0F1A400CE7544 /* CopyToClipboard.swift in Sources */, 340 | 5502FFDF21D0F1A400CE7544 /* Comment.swift in Sources */, 341 | 5502FFE321D0F1A400CE7544 /* ChooseFromMenu.swift in Sources */, 342 | 5502FFD721D0F1A400CE7544 /* ShortcutShareViewController.swift in Sources */, 343 | 5502FFE521D0F1A400CE7544 /* ShowResult.swift in Sources */, 344 | ); 345 | runOnlyForDeploymentPostprocessing = 0; 346 | }; 347 | /* End PBXSourcesBuildPhase section */ 348 | 349 | /* Begin PBXTargetDependency section */ 350 | 5502001A21D10C9200CE7544 /* PBXTargetDependency */ = { 351 | isa = PBXTargetDependency; 352 | target = 5502FF8521D0F06500CE7544 /* ShortcutsSwift */; 353 | targetProxy = 5502001921D10C9200CE7544 /* PBXContainerItemProxy */; 354 | }; 355 | /* End PBXTargetDependency section */ 356 | 357 | /* Begin XCBuildConfiguration section */ 358 | 5502001B21D10C9300CE7544 /* Debug */ = { 359 | isa = XCBuildConfiguration; 360 | buildSettings = { 361 | CODE_SIGN_STYLE = Automatic; 362 | DEVELOPMENT_TEAM = ""; 363 | INFOPLIST_FILE = Tests/Info.plist; 364 | LD_RUNPATH_SEARCH_PATHS = ( 365 | "$(inherited)", 366 | "@executable_path/Frameworks", 367 | "@loader_path/Frameworks", 368 | ); 369 | PRODUCT_BUNDLE_IDENTIFIER = us.pandamonia.ShortcutsSwiftTests; 370 | PRODUCT_NAME = "$(TARGET_NAME)"; 371 | SWIFT_VERSION = 4.2; 372 | TARGETED_DEVICE_FAMILY = "1,2"; 373 | }; 374 | name = Debug; 375 | }; 376 | 5502001C21D10C9300CE7544 /* Release */ = { 377 | isa = XCBuildConfiguration; 378 | buildSettings = { 379 | CODE_SIGN_STYLE = Automatic; 380 | DEVELOPMENT_TEAM = ""; 381 | INFOPLIST_FILE = Tests/Info.plist; 382 | LD_RUNPATH_SEARCH_PATHS = ( 383 | "$(inherited)", 384 | "@executable_path/Frameworks", 385 | "@loader_path/Frameworks", 386 | ); 387 | PRODUCT_BUNDLE_IDENTIFIER = us.pandamonia.ShortcutsSwiftTests; 388 | PRODUCT_NAME = "$(TARGET_NAME)"; 389 | SWIFT_VERSION = 4.2; 390 | TARGETED_DEVICE_FAMILY = "1,2"; 391 | }; 392 | name = Release; 393 | }; 394 | 5502FF8C21D0F06500CE7544 /* Debug */ = { 395 | isa = XCBuildConfiguration; 396 | buildSettings = { 397 | ALWAYS_SEARCH_USER_PATHS = NO; 398 | CLANG_ANALYZER_NONNULL = YES; 399 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 400 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 401 | CLANG_CXX_LIBRARY = "libc++"; 402 | CLANG_ENABLE_MODULES = YES; 403 | CLANG_ENABLE_OBJC_ARC = YES; 404 | CLANG_ENABLE_OBJC_WEAK = YES; 405 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 406 | CLANG_WARN_BOOL_CONVERSION = YES; 407 | CLANG_WARN_COMMA = YES; 408 | CLANG_WARN_CONSTANT_CONVERSION = YES; 409 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 410 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 411 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 412 | CLANG_WARN_EMPTY_BODY = YES; 413 | CLANG_WARN_ENUM_CONVERSION = YES; 414 | CLANG_WARN_INFINITE_RECURSION = YES; 415 | CLANG_WARN_INT_CONVERSION = YES; 416 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 417 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 418 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 419 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 420 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 421 | CLANG_WARN_STRICT_PROTOTYPES = YES; 422 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 423 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 424 | CLANG_WARN_UNREACHABLE_CODE = YES; 425 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 426 | CODE_SIGN_IDENTITY = "iPhone Developer"; 427 | COPY_PHASE_STRIP = NO; 428 | CURRENT_PROJECT_VERSION = 1; 429 | DEBUG_INFORMATION_FORMAT = dwarf; 430 | ENABLE_STRICT_OBJC_MSGSEND = YES; 431 | ENABLE_TESTABILITY = YES; 432 | GCC_C_LANGUAGE_STANDARD = gnu11; 433 | GCC_DYNAMIC_NO_PIC = NO; 434 | GCC_NO_COMMON_BLOCKS = YES; 435 | GCC_OPTIMIZATION_LEVEL = 0; 436 | GCC_PREPROCESSOR_DEFINITIONS = ( 437 | "DEBUG=1", 438 | "$(inherited)", 439 | ); 440 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 441 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 442 | GCC_WARN_UNDECLARED_SELECTOR = YES; 443 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 444 | GCC_WARN_UNUSED_FUNCTION = YES; 445 | GCC_WARN_UNUSED_VARIABLE = YES; 446 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 447 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 448 | MTL_FAST_MATH = YES; 449 | ONLY_ACTIVE_ARCH = YES; 450 | SDKROOT = iphoneos; 451 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 452 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 453 | VERSIONING_SYSTEM = "apple-generic"; 454 | VERSION_INFO_PREFIX = ""; 455 | }; 456 | name = Debug; 457 | }; 458 | 5502FF8D21D0F06500CE7544 /* Release */ = { 459 | isa = XCBuildConfiguration; 460 | buildSettings = { 461 | ALWAYS_SEARCH_USER_PATHS = NO; 462 | CLANG_ANALYZER_NONNULL = YES; 463 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 464 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 465 | CLANG_CXX_LIBRARY = "libc++"; 466 | CLANG_ENABLE_MODULES = YES; 467 | CLANG_ENABLE_OBJC_ARC = YES; 468 | CLANG_ENABLE_OBJC_WEAK = YES; 469 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 470 | CLANG_WARN_BOOL_CONVERSION = YES; 471 | CLANG_WARN_COMMA = YES; 472 | CLANG_WARN_CONSTANT_CONVERSION = YES; 473 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 474 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 475 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 476 | CLANG_WARN_EMPTY_BODY = YES; 477 | CLANG_WARN_ENUM_CONVERSION = YES; 478 | CLANG_WARN_INFINITE_RECURSION = YES; 479 | CLANG_WARN_INT_CONVERSION = YES; 480 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 481 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 482 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 483 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 484 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 485 | CLANG_WARN_STRICT_PROTOTYPES = YES; 486 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 487 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 488 | CLANG_WARN_UNREACHABLE_CODE = YES; 489 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 490 | CODE_SIGN_IDENTITY = "iPhone Developer"; 491 | COPY_PHASE_STRIP = NO; 492 | CURRENT_PROJECT_VERSION = 1; 493 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 494 | ENABLE_NS_ASSERTIONS = NO; 495 | ENABLE_STRICT_OBJC_MSGSEND = YES; 496 | GCC_C_LANGUAGE_STANDARD = gnu11; 497 | GCC_NO_COMMON_BLOCKS = YES; 498 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 499 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 500 | GCC_WARN_UNDECLARED_SELECTOR = YES; 501 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 502 | GCC_WARN_UNUSED_FUNCTION = YES; 503 | GCC_WARN_UNUSED_VARIABLE = YES; 504 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 505 | MTL_ENABLE_DEBUG_INFO = NO; 506 | MTL_FAST_MATH = YES; 507 | SDKROOT = iphoneos; 508 | SWIFT_COMPILATION_MODE = wholemodule; 509 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 510 | VALIDATE_PRODUCT = YES; 511 | VERSIONING_SYSTEM = "apple-generic"; 512 | VERSION_INFO_PREFIX = ""; 513 | }; 514 | name = Release; 515 | }; 516 | 5502FF8F21D0F06500CE7544 /* Debug */ = { 517 | isa = XCBuildConfiguration; 518 | buildSettings = { 519 | CODE_SIGN_IDENTITY = ""; 520 | CODE_SIGN_STYLE = Automatic; 521 | DEFINES_MODULE = YES; 522 | DEVELOPMENT_TEAM = ""; 523 | DYLIB_COMPATIBILITY_VERSION = 1; 524 | DYLIB_CURRENT_VERSION = 1; 525 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 526 | INFOPLIST_FILE = "ShortcutsSwift.xcodeproj/ShortcutsSwift-Info.plist"; 527 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 528 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 529 | LD_RUNPATH_SEARCH_PATHS = ( 530 | "$(inherited)", 531 | "@executable_path/Frameworks", 532 | "@loader_path/Frameworks", 533 | ); 534 | OTHER_SWIFT_FLAGS = "-DXcode"; 535 | PRODUCT_BUNDLE_IDENTIFIER = us.pandamonia.ShortcutsSwift; 536 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 537 | SKIP_INSTALL = YES; 538 | SWIFT_VERSION = 4.2; 539 | TARGETED_DEVICE_FAMILY = "1,2"; 540 | }; 541 | name = Debug; 542 | }; 543 | 5502FF9021D0F06500CE7544 /* Release */ = { 544 | isa = XCBuildConfiguration; 545 | buildSettings = { 546 | CODE_SIGN_IDENTITY = ""; 547 | CODE_SIGN_STYLE = Automatic; 548 | DEFINES_MODULE = YES; 549 | DEVELOPMENT_TEAM = ""; 550 | DYLIB_COMPATIBILITY_VERSION = 1; 551 | DYLIB_CURRENT_VERSION = 1; 552 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 553 | INFOPLIST_FILE = "ShortcutsSwift.xcodeproj/ShortcutsSwift-Info.plist"; 554 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 555 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 556 | LD_RUNPATH_SEARCH_PATHS = ( 557 | "$(inherited)", 558 | "@executable_path/Frameworks", 559 | "@loader_path/Frameworks", 560 | ); 561 | OTHER_SWIFT_FLAGS = "-DXcode"; 562 | PRODUCT_BUNDLE_IDENTIFIER = us.pandamonia.ShortcutsSwift; 563 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 564 | SKIP_INSTALL = YES; 565 | SWIFT_VERSION = 4.2; 566 | TARGETED_DEVICE_FAMILY = "1,2"; 567 | }; 568 | name = Release; 569 | }; 570 | /* End XCBuildConfiguration section */ 571 | 572 | /* Begin XCConfigurationList section */ 573 | 5502001D21D10C9A00CE7544 /* Build configuration list for PBXNativeTarget "ShortcutsSwiftTests" */ = { 574 | isa = XCConfigurationList; 575 | buildConfigurations = ( 576 | 5502001B21D10C9300CE7544 /* Debug */, 577 | 5502001C21D10C9300CE7544 /* Release */, 578 | ); 579 | defaultConfigurationIsVisible = 0; 580 | defaultConfigurationName = Release; 581 | }; 582 | 5502FF8021D0F06500CE7544 /* Build configuration list for PBXProject "ShortcutsSwift" */ = { 583 | isa = XCConfigurationList; 584 | buildConfigurations = ( 585 | 5502FF8C21D0F06500CE7544 /* Debug */, 586 | 5502FF8D21D0F06500CE7544 /* Release */, 587 | ); 588 | defaultConfigurationIsVisible = 0; 589 | defaultConfigurationName = Release; 590 | }; 591 | 5502FF8E21D0F06500CE7544 /* Build configuration list for PBXNativeTarget "ShortcutsSwift" */ = { 592 | isa = XCConfigurationList; 593 | buildConfigurations = ( 594 | 5502FF8F21D0F06500CE7544 /* Debug */, 595 | 5502FF9021D0F06500CE7544 /* Release */, 596 | ); 597 | defaultConfigurationIsVisible = 0; 598 | defaultConfigurationName = Release; 599 | }; 600 | /* End XCConfigurationList section */ 601 | }; 602 | rootObject = 5502FF7D21D0F06500CE7544 /* Project object */; 603 | } 604 | -------------------------------------------------------------------------------- /ShortcutsSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ShortcutsSwift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ShortcutsSwift.xcodeproj/xcshareddata/xcschemes/ShortcutsSwift.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Tests/AggrandizementTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AggrandizementTests.swift 3 | // ShortcutsSwiftTests 4 | // 5 | // Created by Alejandro Martinez on 02/01/2019. 6 | // Copyright © 2019 Pandamonia LLC. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import ShortcutsSwift 11 | 12 | class AggrandizementTests: XCTestCase { 13 | 14 | func testDictionary() { 15 | let dictionaryVariable = actionOutput() 16 | _ = buildShortcut( 17 | dictionary(["number": 42]).savingOutput(to: dictionaryVariable) + 18 | showResult("\(dictionaryVariable.with(valueForKey: "number"))") 19 | ) 20 | } 21 | 22 | func testDateFormat() { 23 | let result = actionOutput() 24 | let dateFormat = result.with(dateFormat: .howLongAgoUntil) 25 | _ = buildShortcut( 26 | getBatteryLevel().savingOutput(to: result) 27 | + showResult("Test Aggrandizements \(dateFormat)") 28 | ) 29 | } 30 | 31 | func testProperty() { 32 | let result = actionOutput() 33 | let prop = result.with(propertyName: .name, userInfo: .fileSize) 34 | _ = buildShortcut( 35 | getBatteryLevel().savingOutput(to: result) 36 | + showResult("Test Aggrandizements \(prop)") 37 | ) 38 | } 39 | 40 | func testCustomNumberProperty() { 41 | let result = actionOutput() 42 | let count = result.with(propertyName: .custom("Count"), userInfo: .number(3)) 43 | _ = buildShortcut( 44 | getBatteryLevel().savingOutput(to: result) 45 | + showResult("Test Aggrandizements \(count)") 46 | ) 47 | } 48 | 49 | func testCoercion() { 50 | let result = actionOutput() 51 | let coercion = result.with(type: .article) 52 | _ = buildShortcut( 53 | getBatteryLevel().savingOutput(to: result) 54 | + showResult("Test Aggrandizements \(coercion)") 55 | ) 56 | } 57 | 58 | func _testCrash() { 59 | let result = actionOutput() 60 | print(" \(result)".unicodeScalars.map({ $0.value })) // Count 79 61 | print(" \(result)".unicodeScalars.map({ $0.value })) // Count 78 62 | _ = buildShortcut( 63 | getBatteryLevel().savingOutput(to: result) 64 | + showResult(" \(result)") // This first space is not a normal space. 65 | ) 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tests/ShortcutsSwiftTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import ShortcutsSwift 3 | 4 | class ShortcutsSwiftTests: XCTestCase { 5 | /// Tests that the battery level example compiles. 6 | func testBatteryExample() { 7 | let batteryLevel = actionOutput() 8 | _ = buildShortcut( 9 | comment("This Shortcut was generated in Swift.") + 10 | getBatteryLevel().savingOutput(to: batteryLevel) + 11 | ifLessThan(20, ifTrue: ( 12 | setLowPowerMode(true) + 13 | showResult("Your battery is at \(batteryLevel)%, you might want to charge it.") 14 | ), ifFalse: ( 15 | showResult("Your battery is at \(batteryLevel)%, you're probably fine for now.") 16 | )) 17 | ) 18 | } 19 | 20 | /// Tests that the clap along example compiles. 21 | func testClapAlong() { 22 | _ = buildShortcut( 23 | comment("This Shortcut was generated in Swift.") + 24 | ask(question: "WHAT 👏 DO 👏 YOU 👏 WANT 👏 TO 👏 SAY") + 25 | changeCase(to: .uppercase) + 26 | replaceText("[\\s]", replaceWith: " 👏 ", regularExpression: true) + 27 | chooseFromMenu(items: [ 28 | ("Share", share()), 29 | ("Copy to Clipboard", copyToClipboard()), 30 | ]) 31 | ) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | pool: 2 | vmImage: 'macOS 10.13' 3 | 4 | steps: 5 | - script: | 6 | sudo xcode-select -switch /Applications/Xcode_10.app 7 | bundle install 8 | displayName: "Setup Environment" 9 | 10 | - script: | 11 | bundle exec fastlane build 12 | displayName: "Build" 13 | 14 | - task: PublishBuildArtifacts@1 15 | inputs: 16 | pathtoPublish: "build" 17 | artifactName: "Build logs" 18 | condition: succeededOrFailed() 19 | displayName: "Store Build Log" 20 | 21 | - script: | 22 | bundle exec fastlane test 23 | displayName: "Test" 24 | 25 | - task: PublishBuildArtifacts@1 26 | inputs: 27 | pathtoPublish: "test" 28 | artifactName: "Test logs" 29 | condition: succeededOrFailed() 30 | displayName: "Store Test Log" 31 | -------------------------------------------------------------------------------- /banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a2/shortcuts-swift/45f825c584dccafb0a1cf2fa836404fbaf49ecaf/banner.png -------------------------------------------------------------------------------- /fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | opt_out_usage 2 | default_platform(:ios) 3 | 4 | platform :ios do 5 | desc "Build for testing" 6 | lane :build do 7 | scan( 8 | scheme: "ShortcutsSwift", 9 | configuration: "Debug", 10 | build_for_testing: true, 11 | devices: ["iPhone 7"], 12 | code_coverage: true, 13 | derived_data_path: "DerivedData", 14 | buildlog_path: "build", 15 | output_directory: "build", 16 | output_types: "junit" 17 | ) 18 | end 19 | 20 | desc "Test without building" 21 | lane :test do 22 | scan( 23 | scheme: "ShortcutsSwift", 24 | configuration: "Debug", 25 | test_without_building: true, 26 | devices: ["iPhone 7"], 27 | code_coverage: true, 28 | derived_data_path: "DerivedData", 29 | buildlog_path: "test", 30 | output_directory: "test", 31 | output_types: "junit" 32 | ) 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /fastlane/README.md: -------------------------------------------------------------------------------- 1 | fastlane documentation 2 | ================ 3 | # Installation 4 | 5 | Make sure you have the latest version of the Xcode command line tools installed: 6 | 7 | ``` 8 | xcode-select --install 9 | ``` 10 | 11 | Install _fastlane_ using 12 | ``` 13 | [sudo] gem install fastlane -NV 14 | ``` 15 | or alternatively using `brew cask install fastlane` 16 | 17 | # Available Actions 18 | ## iOS 19 | ### ios build 20 | ``` 21 | fastlane ios build 22 | ``` 23 | Build for testing 24 | ### ios test 25 | ``` 26 | fastlane ios test 27 | ``` 28 | Test without building 29 | 30 | ---- 31 | 32 | This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run. 33 | More information about fastlane can be found on [fastlane.tools](https://fastlane.tools). 34 | The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools). 35 | -------------------------------------------------------------------------------- /feed.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Shortcuts Swift", 3 | "subtitle": "Write Shortcuts in Playgrounds", 4 | "publisherName": "Alexsander Akers", 5 | "feedIdentifier": "io.a2", 6 | "contactURL": "https://github.com/a2/shortcuts-swift", 7 | "formatVersion": "1.2", 8 | "documents": [ 9 | { 10 | "title": "Shortcuts Swift", 11 | "overviewSubtitle": "Write Shortcuts in Playgrounds", 12 | "description": "The Shortcuts app makes use of a graphic user interface to create Shortcuts. In this Playground Book, you can write your own Shortcuts using Swift on your iPad in the Playgrounds app.", 13 | "contentIdentifier": "io.a2.shortcuts-swift", 14 | "contentVersion": "1.0", 15 | "url": "https://github.com/a2/shortcuts-swift/releases/download/1.0/ShortcutsSwift.playgroundbook.zip", 16 | "publishedDate": "2018-12-23T16:08:44+0000", 17 | "lastUpdatedDate": "2018-12-23T16:31:59+0000", 18 | "sha512": "9daf5f0eeb901e0512060c89dc799e13309a3be52ab26801ba051da45e9e011871880b0efb52426f68c9083eb0a3c6e96306ef488ebcf77556c77b6c56a96b65", 19 | "thumbnailURL": "https://raw.githubusercontent.com/a2/shortcuts-swift/master/ShortcutsSwift.playgroundbook/Contents/PrivateResources/Cover.png", 20 | "bannerImageURL": "https://raw.githubusercontent.com/a2/shortcuts-swift/master/banner.png", 21 | "previewImageURLs": [ 22 | "https://raw.githubusercontent.com/a2/shortcuts-swift/master/preview.png" 23 | ], 24 | "additionalInformation": [ 25 | { 26 | "name": "Publisher", 27 | "value": "Alexsander Akers" 28 | }, 29 | { 30 | "name": "Version", 31 | "value": "1.0" 32 | }, 33 | { 34 | "type": "date", 35 | "name": "Released", 36 | "value": "2018-12-23T16:08:44+0000" 37 | }, 38 | { 39 | "name": "Languages", 40 | "value": "English" 41 | } 42 | ] 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a2/shortcuts-swift/45f825c584dccafb0a1cf2fa836404fbaf49ecaf/preview.png --------------------------------------------------------------------------------