├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── ci.yml ├── .gitignore ├── .swiftlint.yml ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── contents.xcworkspacedata ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Example.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── Example.xcscheme ├── Example ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── appIcon20pt@2x.png │ │ ├── appIcon20pt@3x.png │ │ ├── appIcon29pt@2x.png │ │ ├── appIcon29pt@3x.png │ │ ├── appIcon40pt@2x.png │ │ ├── appIcon40pt@3x.png │ │ ├── appIcon60pt@2x.png │ │ └── appIcon60pt@3x.png │ ├── Contents.json │ ├── periscope │ │ ├── Contents.json │ │ └── pe-background.imageset │ │ │ ├── Contents.json │ │ │ └── IMG_3582.png │ ├── skype │ │ ├── Contents.json │ │ └── skype-background.imageset │ │ │ ├── Contents.json │ │ │ └── skype-background@2x.png │ ├── spotify │ │ ├── Contents.json │ │ ├── sp-add-icon.imageset │ │ │ ├── Contents.json │ │ │ └── sp-add-icon@2x.png │ │ ├── sp-background.imageset │ │ │ ├── Contents.json │ │ │ └── IMG_3579.png │ │ ├── sp-header-icon.imageset │ │ │ ├── Contents.json │ │ │ └── sp-header-icon@2x.png │ │ ├── sp-radio-icon.imageset │ │ │ ├── Contents.json │ │ │ └── sp-radio-icon@2x.png │ │ ├── sp-remove-icon.imageset │ │ │ ├── Contents.json │ │ │ └── sp-remove-icon@2x.png │ │ ├── sp-share-icon.imageset │ │ │ ├── Contents.json │ │ │ └── sp-share-icon@2x.png │ │ └── sp-view-album-icon.imageset │ │ │ ├── Contents.json │ │ │ └── sp-view-album-icon@2x.png │ ├── tweetbot │ │ ├── Contents.json │ │ └── tb-background.imageset │ │ │ ├── Contents.json │ │ │ └── IMG_3578.png │ ├── twitter │ │ ├── Contents.json │ │ ├── tw-background.imageset │ │ │ ├── Contents.json │ │ │ └── IMG_3577.png │ │ ├── tw-remer.imageset │ │ │ ├── Contents.json │ │ │ └── tw-remer.jpg │ │ └── tw-xmartlabs.imageset │ │ │ ├── Contents.json │ │ │ └── tw-xmartlabs.png │ ├── xmartlabs │ │ ├── Contents.json │ │ ├── xl_header.imageset │ │ │ ├── Contents.json │ │ │ └── header.png │ │ └── xmartlabs_logo.imageset │ │ │ ├── Contents.json │ │ │ └── xmartlabsLogoCircle@2x.png │ └── youtube │ │ ├── Contents.json │ │ ├── yt-add-to-playlist-icon.imageset │ │ ├── Contents.json │ │ └── yt-add-to-playlist-icon.png │ │ ├── yt-add-to-watch-later-icon.imageset │ │ ├── Contents.json │ │ └── yt-add-watch-later-icon.png │ │ ├── yt-background.imageset │ │ ├── Contents.json │ │ └── IMG_3581.png │ │ ├── yt-cancel-icon.imageset │ │ ├── Contents.json │ │ └── yt-cancel-icon.png │ │ └── yt-share-icon.imageset │ │ ├── Contents.json │ │ └── yt-share-icon.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── CustomActionControllers │ ├── Periscope │ │ ├── Periscope.swift │ │ └── PeriscopeCell.xib │ ├── Skype │ │ ├── Skype.swift │ │ └── SkypeCell.xib │ ├── Spotify │ │ ├── Spotify.swift │ │ └── SpotifyCell.xib │ ├── Tweetbot │ │ ├── Tweetbot.swift │ │ └── TweetbotCell.xib │ ├── Twitter │ │ ├── Twitter.swift │ │ └── TwitterCell.xib │ └── Youtube │ │ ├── Youtube.swift │ │ └── YoutubeCell.xib ├── Info.plist ├── MainViewController.swift ├── PeriscopeExampleViewController.swift ├── SkypeExampleViewController.swift ├── SpotifyExampleViewController.swift ├── TweetbotExampleViewController.swift ├── TwitterExampleViewController.swift ├── UITests │ ├── ExampleUITests.swift │ └── Info.plist └── YouTubeExampleViewController.swift ├── LICENSE ├── Media ├── demo_periscope.gif ├── demo_skype.gif ├── demo_spotify.gif ├── demo_tweetbot.gif ├── demo_twitter.gif └── demo_youtube.gif ├── Package.swift ├── README.md ├── Resource └── ActionCell.xib ├── Source ├── Action.swift ├── ActionCell.swift ├── ActionController.swift ├── ActionControllerSettings.swift ├── ActionData.swift ├── DynamicCollectionViewFlowLayout.swift ├── Info.plist └── XLActionController.h ├── Tests ├── Info.plist └── XLActionControllerTests.swift ├── XLActionController.png ├── XLActionController.podspec ├── XLActionController.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── XLActionController.xcscheme └── XLActionController.xcworkspace ├── contents.xcworkspacedata └── xcshareddata └── IDEWorkspaceChecks.plist /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: xmartlabs # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Before submitting issues ... 2 | 3 | - Make sure you are using XLActionController [latest release](https://github.com/xmartlabs/XLActionController/releases) or master branch version. 4 | - Make sure your Xcode version is the latest stable one. 5 | - Check if the issue was [already reported or fixed](https://github.com/xmartlabs/XLActionController/issues?utf8=%E2%9C%93&q=is%3Aissue). We add labels to each issue in order to easily find related issues. If you found a match add a brief comment "I have the same problem" or "+1". 6 | 7 | When submitting issues, please provide the following information to help maintainers to fix the problem faster: 8 | 9 | - Environment: XLActionController, Xcode and iOS version you are using. 10 | - In case of reporting errors, provide Xcode console output of stack trace or code compilation error. 11 | - Any other additional detail such as example code that you think it would be useful to understand, reproduce and solve the problem. 12 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/.github/PULL_REQUEST_TEMPLATE.md -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: XLActionController CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | 9 | jobs: 10 | iOS: 11 | runs-on: macOS-latest 12 | strategy: 13 | matrix: 14 | destination: ['platform=iOS Simulator,OS=14.4,name=iPhone 11'] 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Build and test library 18 | run: set -o pipefail && xcodebuild -project XLActionController.xcodeproj -scheme 'XLActionController' -sdk 'iphonesimulator' -destination "${{ matrix.destination }}" -configuration Debug ONLY_ACTIVE_ARCH=NO test | xcpretty -c 19 | - name: Build Example Debug 20 | run: set -o pipefail && xcodebuild -project Example.xcodeproj -scheme 'Example' -sdk 'iphonesimulator' -destination "${{ matrix.destination }}" -configuration Debug ONLY_ACTIVE_ARCH=NO build | xcpretty -c 21 | - name: Build Example Release 22 | run: set -o pipefail && xcodebuild -project Example.xcodeproj -scheme 'Example' -sdk 'iphonesimulator' -destination "${{ matrix.destination }}" -configuration Release ONLY_ACTIVE_ARCH=NO build | xcpretty -c 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | */build/* 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | profile 14 | *.moved-aside 15 | DerivedData 16 | .idea/ 17 | *.hmap 18 | *.xccheckout 19 | .build/ 20 | 21 | #CocoaPods 22 | Pods 23 | Tests/Pods 24 | Tests/Podfile.lock 25 | Examples/Objective-C/Podfile.lock 26 | Examples/Swift/Podfile.lock -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Source 3 | - Example 4 | disabled_rules: 5 | #- colon 6 | #- control_statement 7 | - file_length 8 | - force_cast 9 | - function_body_length 10 | #- leading_whitespace 11 | - line_length 12 | #- nesting 13 | #- operator_whitespace 14 | #- return_arrow_whitespace 15 | #- todo 16 | #- trailing_newline 17 | - trailing_whitespace 18 | - type_body_length 19 | #- type_name 20 | #- variable_name 21 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ### [5.1.0](https://github.com/xmartlabs/XLActionController/releases/tag/5.1.0) 6 | 7 | * Added the ability to adjust Cancel View's Title font and size. (#145) 8 | * Support for SPM (#144, #146) 9 | 10 | ### [5.0.2](https://github.com/xmartlabs/XLActionController/releases/tag/5.0.2) 11 | 12 | * Fix incorrect top inset and content offset (#126) 13 | * Support setting cancel view's title color (#129) 14 | * Fix issue introduced with last release that would crash an app when using one of the subspecs 15 | 16 | ### [5.0.1](https://github.com/xmartlabs/XLActionController/releases/tag/5.0.1) 17 | 18 | * Updates for Xcode 11 19 | 20 | ### [5.0.0](https://github.com/xmartlabs/XLActionController/releases/tag/5.0.0) 21 | 22 | * Swift 5.0 source compability. 23 | 24 | ### [4.1.0](https://github.com/xmartlabs/XLActionController/releases/tag/4.1.0) 25 | 26 | * Swift 4.2 source compability. 27 | 28 | ### [4.0.1](https://github.com/xmartlabs/XLActionController/releases/tag/4.0.1) 29 | 30 | * Bug fixes and stability improvements. 31 | * Added support for iphone X. 32 | 33 | ### [4.0.0](https://github.com/xmartlabs/XLActionController/releases/tag/4.0.0) 34 | 35 | * Support for Swift 4. 36 | * Added customizable background color to the Skype action controller, [PR #52](https://github.com/xmartlabs/XLActionController/pull/52) 37 | * Using status bar style from settings in iOS 10, [PR #53](https://github.com/xmartlabs/XLActionController/pull/53) 38 | 39 | ### [3.0.1](https://github.com/xmartlabs/XLActionController/releases/tag/3.0.1) 40 | 41 | * Fixed crash when using ActionCell.xib, [PR #31](https://github.com/xmartlabs/XLActionController/pull/31). 42 | 43 | ### [Swift 3 Support](https://github.com/xmartlabs/XLActionController/releases/tag/3.0.0) 44 | 45 | * Swift 3 and Xcode 8 support, [PR #24](https://github.com/xmartlabs/XLActionController/pull/24) 46 | 47 | ### [2.1.0](https://github.com/xmartlabs/XLActionController/releases/tag/2.1.0) 48 | 49 | * **Breaking change**: `actionTitleLabelConstraintToContainer` and `actionTitleLabelConstraintToImageView` was removed from `ActionCell` class. You must delete these outlets from your xib files, [PR #23](https://github.com/xmartlabs/XLActionController/pull/23). 50 | * **Breaking change**: actions' handlers are now executed after the action controller was completely dismissed, [PR #22](https://github.com/xmartlabs/XLActionController/pull/22). 51 | * Fixed duplicated execution of actions, [PR #22](https://github.com/xmartlabs/XLActionController/pull/22). 52 | 53 | ### [2.0.0](https://github.com/xmartlabs/XLActionController/releases/tag/2.0.0) 54 | 55 | * Bug fixes and stability improvements. 56 | * added support for Xcode 7.3 and swift 2.2. 57 | 58 | ### [1.0.0](https://github.com/xmartlabs/XLActionController/releases/tag/1.0.0) 59 | Released on 2015-12-11. This is the initial version. 60 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing Guidelines 2 | -------------------------------------------------- 3 | 4 | This document provides general guidelines about how to contribute to the project. Keep in mind these important things before you start contributing. 5 | 6 | ### Asking Questions 7 | 8 | We do not use github issues for general library support. We think this questions should be posted on stack overflow using [XlPagerTabStrip](http://http://stackoverflow.com/questions/tagged/xlactioncontroller) tag. 9 | 10 | ### Reporting issues 11 | 12 | * Use [github issues](https://github.com/xmartlabs/XLActionController/issues) to report a bug. 13 | * Before creating a new issue: 14 | * Make sure you are using the [latest release](https://github.com/xmartlabs/XLActionController/releases). 15 | * Check if the issue was [already reported or fixed](https://github.com/xmartlabs/XLActionController/issues?utf8=%E2%9C%93&q=is%3Aissue). Notice that it may not be released yet. 16 | * If you found a match add a brief comment "I have the same problem" or "+1". This helps prioritize the issues addressing the most common and critical first. If possible add additional information to help us reproduce and fix the issue. Please use your best judgement. 17 | * Reporting issues: 18 | * Please include the following information to help maintainers to fix the problem faster: 19 | * Xcode version you are using. 20 | * iOS version you are targeting. 21 | * Full Xcode console output of stack trace or code compilation error. 22 | * Any other additional detail you think it would be useful to understand and solve the problem. 23 | 24 | 25 | ### Pull requests 26 | 27 | The easiest way to start contributing is searching open issues by `help wanted` tag. We also add a `difficulty` tag (difficulty: easy, difficulty: moderate, difficulty: hard) in order to give an idea of how complex it can be to implement the feature according maintainers project experience. 28 | 29 | * Add test coverage to the feature or fix. We only accept new feature pull requests that have related test coverage. This allows us to keep the library stable as we move forward. 30 | * Remember to document the new feature. We do not accept new feature pull requests without its associated documentation. 31 | * In case of a new feature please update the example project showing the feature. 32 | * Please only one fix or feature per pull request. This will increase the chances your feature will be merged. 33 | 34 | 35 | ###### Suggested git workflow to contribute 36 | 37 | 1. Fork the XLActionController repository. 38 | 2. Clone your forked project into your developer machine: `git clone git@github.com:/XLActionController.git` 39 | 3. Add the original project repo as upstream repository in your forked project: `git remote add upstream git@github.com:xmartlabs/XLActionController.git` 40 | 4. Before starting a new feature make sure your forked master branch is synchronized upstream master branch. Considering you do not mere your pull request into master you can run: `git checkout master` and then `git pull upstream master`. Optionally `git push origin master`. 41 | 5. Create a new branch. Note that the starting point is the upstream master branch HEAD. `git checkout -b my-feature-name` 42 | 6. Stage all your changes `git add .` and commit them `git commit -m "Your commit message"` 43 | 7. Make sure your branch is up to date with upstream master, `git pull --rebase upstream master`, resolve conflicts if necessary. This will move your commit to the top of git stack. 44 | 8. Squash your commits into one commit. `git rebase -i HEAD~6` considering you did 6 commits. 45 | 9. Push your branch into your forked remote repository. 46 | 10. Create a new pull request adding any useful comment. 47 | 48 | 49 | ###### Code style and conventions 50 | 51 | We try to follow our [swift style guide](https://github.com/xmartlabs/Swift-Style-Guide). Following it is not strictly necessary to contribute and to have a pull request accepted but project maintainers try to follow it. We would love to hear your ideas to improve our code style and conventions. Feel free to contribute. 52 | 53 | 54 | ### Feature proposal 55 | 56 | We would love to hear your ideas and make a discussions about it. 57 | 58 | * Use github issues to make feature proposals. 59 | * We use `type: feature request` label to mark all [feature request issues](https://github.com/xmartlabs/XLActionController/labels/type%3A%20feature%20request). 60 | * Before submitting your proposal make sure there is no similar feature request. If you found a match feel free to join the discussion or just add a brief "+1" if you think the feature is worth implementing. 61 | * Be as specific as possible providing a precise explanation of feature request so anyone can understand the problem and the benefits of solving it. 62 | -------------------------------------------------------------------------------- /Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example.xcodeproj/xcshareddata/xcschemes/Example.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 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // AppDelegate.swift 2 | // XLActionController ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | 27 | @UIApplicationMain 28 | class AppDelegate: UIResponder, UIApplicationDelegate { 29 | 30 | var window: UIWindow? 31 | 32 | 33 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 34 | // Override point for customization after application launch. 35 | return true 36 | } 37 | 38 | func applicationWillResignActive(_ application: UIApplication) { 39 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 40 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 41 | } 42 | 43 | func applicationDidEnterBackground(_ application: UIApplication) { 44 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 45 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 46 | } 47 | 48 | func applicationWillEnterForeground(_ application: UIApplication) { 49 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 50 | } 51 | 52 | func applicationDidBecomeActive(_ application: UIApplication) { 53 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 54 | } 55 | 56 | func applicationWillTerminate(_ application: UIApplication) { 57 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /Example/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "appIcon20pt@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "appIcon20pt@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "appIcon29pt@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "appIcon29pt@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "appIcon40pt@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "appIcon40pt@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "appIcon60pt@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "appIcon60pt@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "idiom" : "ios-marketing", 53 | "size" : "1024x1024", 54 | "scale" : "1x" 55 | } 56 | ], 57 | "info" : { 58 | "version" : 1, 59 | "author" : "xcode" 60 | } 61 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/AppIcon.appiconset/appIcon20pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/AppIcon.appiconset/appIcon20pt@2x.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/AppIcon.appiconset/appIcon20pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/AppIcon.appiconset/appIcon20pt@3x.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/AppIcon.appiconset/appIcon29pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/AppIcon.appiconset/appIcon29pt@2x.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/AppIcon.appiconset/appIcon29pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/AppIcon.appiconset/appIcon29pt@3x.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/AppIcon.appiconset/appIcon40pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/AppIcon.appiconset/appIcon40pt@2x.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/AppIcon.appiconset/appIcon40pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/AppIcon.appiconset/appIcon40pt@3x.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/AppIcon.appiconset/appIcon60pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/AppIcon.appiconset/appIcon60pt@2x.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/AppIcon.appiconset/appIcon60pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/AppIcon.appiconset/appIcon60pt@3x.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/periscope/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/periscope/pe-background.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "IMG_3582.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/periscope/pe-background.imageset/IMG_3582.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/periscope/pe-background.imageset/IMG_3582.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/skype/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/skype/skype-background.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "skype-background@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/skype/skype-background.imageset/skype-background@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/skype/skype-background.imageset/skype-background@2x.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/spotify/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/spotify/sp-add-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "sp-add-icon@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/spotify/sp-add-icon.imageset/sp-add-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/spotify/sp-add-icon.imageset/sp-add-icon@2x.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/spotify/sp-background.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "IMG_3579.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/spotify/sp-background.imageset/IMG_3579.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/spotify/sp-background.imageset/IMG_3579.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/spotify/sp-header-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "sp-header-icon@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/spotify/sp-header-icon.imageset/sp-header-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/spotify/sp-header-icon.imageset/sp-header-icon@2x.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/spotify/sp-radio-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "sp-radio-icon@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/spotify/sp-radio-icon.imageset/sp-radio-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/spotify/sp-radio-icon.imageset/sp-radio-icon@2x.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/spotify/sp-remove-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "sp-remove-icon@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/spotify/sp-remove-icon.imageset/sp-remove-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/spotify/sp-remove-icon.imageset/sp-remove-icon@2x.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/spotify/sp-share-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "sp-share-icon@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/spotify/sp-share-icon.imageset/sp-share-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/spotify/sp-share-icon.imageset/sp-share-icon@2x.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/spotify/sp-view-album-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "sp-view-album-icon@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/spotify/sp-view-album-icon.imageset/sp-view-album-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/spotify/sp-view-album-icon.imageset/sp-view-album-icon@2x.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/tweetbot/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/tweetbot/tb-background.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "IMG_3578.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/tweetbot/tb-background.imageset/IMG_3578.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/tweetbot/tb-background.imageset/IMG_3578.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/twitter/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/twitter/tw-background.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "IMG_3577.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/twitter/tw-background.imageset/IMG_3577.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/twitter/tw-background.imageset/IMG_3577.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/twitter/tw-remer.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "tw-remer.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/twitter/tw-remer.imageset/tw-remer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/twitter/tw-remer.imageset/tw-remer.jpg -------------------------------------------------------------------------------- /Example/Assets.xcassets/twitter/tw-xmartlabs.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "tw-xmartlabs.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/twitter/tw-xmartlabs.imageset/tw-xmartlabs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/twitter/tw-xmartlabs.imageset/tw-xmartlabs.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/xmartlabs/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/xmartlabs/xl_header.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "header.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/xmartlabs/xl_header.imageset/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/xmartlabs/xl_header.imageset/header.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/xmartlabs/xmartlabs_logo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "xmartlabsLogoCircle@2x.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/xmartlabs/xmartlabs_logo.imageset/xmartlabsLogoCircle@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/xmartlabs/xmartlabs_logo.imageset/xmartlabsLogoCircle@2x.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/youtube/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/youtube/yt-add-to-playlist-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "yt-add-to-playlist-icon.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/youtube/yt-add-to-playlist-icon.imageset/yt-add-to-playlist-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/youtube/yt-add-to-playlist-icon.imageset/yt-add-to-playlist-icon.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/youtube/yt-add-to-watch-later-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "yt-add-watch-later-icon.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/youtube/yt-add-to-watch-later-icon.imageset/yt-add-watch-later-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/youtube/yt-add-to-watch-later-icon.imageset/yt-add-watch-later-icon.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/youtube/yt-background.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "IMG_3581.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/youtube/yt-background.imageset/IMG_3581.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/youtube/yt-background.imageset/IMG_3581.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/youtube/yt-cancel-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "yt-cancel-icon.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/youtube/yt-cancel-icon.imageset/yt-cancel-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/youtube/yt-cancel-icon.imageset/yt-cancel-icon.png -------------------------------------------------------------------------------- /Example/Assets.xcassets/youtube/yt-share-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "yt-share-icon.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Assets.xcassets/youtube/yt-share-icon.imageset/yt-share-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Example/Assets.xcassets/youtube/yt-share-icon.imageset/yt-share-icon.png -------------------------------------------------------------------------------- /Example/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Example/CustomActionControllers/Periscope/Periscope.swift: -------------------------------------------------------------------------------- 1 | // Periscope.swift 2 | // Periscope ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | #if IMPORT_BASE_XLACTIONCONTROLLER 27 | import XLActionController 28 | #endif 29 | 30 | public class PeriscopeCell: ActionCell { 31 | 32 | public override init(frame: CGRect) { 33 | super.init(frame: frame) 34 | initialize() 35 | } 36 | 37 | required public init?(coder aDecoder: NSCoder) { 38 | super.init(coder: aDecoder) 39 | } 40 | 41 | public override func awakeFromNib() { 42 | super.awakeFromNib() 43 | initialize() 44 | } 45 | 46 | func initialize() { 47 | backgroundColor = .white 48 | let backgroundView = UIView() 49 | backgroundView.backgroundColor = UIColor(white: 0.0, alpha: 0.15) 50 | selectedBackgroundView = backgroundView 51 | separatorView?.backgroundColor = UIColor(red: 224/255.0, green: 224/255.0, blue: 224/255.0, alpha: 1.0) 52 | } 53 | } 54 | 55 | 56 | public class PeriscopeSection: Section { 57 | public override init() { 58 | super.init() 59 | self.data = () 60 | } 61 | } 62 | 63 | public class PeriscopeHeader: UICollectionReusableView { 64 | 65 | lazy var label: UILabel = { 66 | let label = UILabel() 67 | label.textColor = UIColor(red: 171/255.0, green: 187/255.0, blue: 191/255.0, alpha: 1.0) 68 | label.numberOfLines = 0 69 | label.lineBreakMode = .byWordWrapping 70 | label.font = .systemFont(ofSize: 17.0) 71 | return label 72 | }() 73 | 74 | public override init(frame: CGRect) { 75 | super.init(frame: frame) 76 | backgroundColor = UIColor(white: 0.95, alpha: 1.0) 77 | addSubview(label) 78 | } 79 | 80 | required public init?(coder aDecoder: NSCoder) { 81 | fatalError("init(coder:) has not been implemented") 82 | } 83 | } 84 | 85 | public class PeriscopeActionController: ActionController { 86 | 87 | required public init?(coder aDecoder: NSCoder) { 88 | super.init(coder: aDecoder) 89 | } 90 | 91 | public override init(nibName nibNameOrNil: String? = nil, bundle nibBundleOrNil: Bundle? = nil) { 92 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 93 | 94 | collectionViewLayout.minimumLineSpacing = -0.5 95 | collectionViewLayout.sectionInset = UIEdgeInsets(top: -0.5, left: 0, bottom: 0, right: 0) 96 | 97 | settings.behavior.hideOnScrollDown = false 98 | settings.animation.scale = nil 99 | settings.animation.present.duration = 0.6 100 | settings.animation.dismiss.duration = 0.5 101 | settings.animation.dismiss.options = .curveEaseIn 102 | settings.animation.dismiss.offset = 30 103 | 104 | cellSpec = .nibFile(nibName: "PeriscopeCell", bundle: Bundle(for: PeriscopeCell.self), height: { _ in 60}) 105 | sectionHeaderSpec = .cellClass(height: { _ in 5 }) 106 | headerSpec = .cellClass(height: { [weak self] (headerData: String) in 107 | guard let me = self else { return 0 } 108 | let label = UILabel(frame: CGRect(x: 0, y: 0, width: me.view.frame.width - 40, height: CGFloat.greatestFiniteMagnitude)) 109 | label.numberOfLines = 0 110 | label.font = .systemFont(ofSize: 17.0) 111 | label.text = headerData 112 | label.sizeToFit() 113 | return label.frame.size.height + 20 114 | }) 115 | 116 | onConfigureHeader = { [weak self] header, headerData in 117 | guard let me = self else { return } 118 | header.label.frame = CGRect(x: 0, y: 0, width: me.view.frame.size.width - 40, height: CGFloat.greatestFiniteMagnitude) 119 | header.label.text = headerData 120 | header.label.sizeToFit() 121 | header.label.center = CGPoint(x: header.frame.size.width / 2, y:header.frame.size.height / 2) 122 | } 123 | onConfigureSectionHeader = { sectionHeader, sectionHeaderData in 124 | sectionHeader.backgroundColor = UIColor(white: 0.95, alpha: 1.0) 125 | } 126 | onConfigureCellForAction = { [weak self] cell, action, indexPath in 127 | cell.setup(action.data, detail: nil, image: nil) 128 | cell.separatorView?.isHidden = indexPath.item == self!.collectionView.numberOfItems(inSection: indexPath.section) - 1 129 | cell.alpha = action.enabled ? 1.0 : 0.5 130 | cell.actionTitleLabel?.textColor = action.style == .destructive ? UIColor(red: 210/255.0, green: 77/255.0, blue: 56/255.0, alpha: 1.0) : UIColor(red: 0.28, green: 0.64, blue: 0.76, alpha: 1.0) 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Example/CustomActionControllers/Periscope/PeriscopeCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Example/CustomActionControllers/Skype/Skype.swift: -------------------------------------------------------------------------------- 1 | // Skype.swift 2 | // Skype ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | #if IMPORT_BASE_XLACTIONCONTROLLER 27 | import XLActionController 28 | #endif 29 | 30 | open class SkypeCell: UICollectionViewCell { 31 | 32 | @IBOutlet open weak var actionTitleLabel: UILabel! 33 | 34 | public override init(frame: CGRect) { 35 | super.init(frame: frame) 36 | initialize() 37 | } 38 | 39 | required public init?(coder aDecoder: NSCoder) { 40 | super.init(coder: aDecoder) 41 | } 42 | 43 | open override func awakeFromNib() { 44 | super.awakeFromNib() 45 | initialize() 46 | } 47 | 48 | func initialize() { 49 | backgroundColor = .clear 50 | actionTitleLabel?.textColor = .darkGray 51 | let backgroundView = UIView() 52 | backgroundView.backgroundColor = backgroundColor 53 | selectedBackgroundView = backgroundView 54 | } 55 | } 56 | 57 | 58 | open class SkypeActionController: ActionController { 59 | 60 | static let bottomPadding: CGFloat = 20.0 61 | 62 | open var backgroundColor: UIColor = UIColor(red: 18/255.0, green: 165/255.0, blue: 244/255.0, alpha: 1.0) 63 | 64 | fileprivate var contextView: ContextView! 65 | fileprivate var normalAnimationRect: UIView! 66 | fileprivate var springAnimationRect: UIView! 67 | 68 | let topSpace = CGFloat(40) 69 | 70 | public override init(nibName nibNameOrNil: String? = nil, bundle nibBundleOrNil: Bundle? = nil) { 71 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 72 | 73 | cellSpec = .nibFile(nibName: "SkypeCell", bundle: Bundle(for: SkypeCell.self), height: { _ in 60 }) 74 | settings.animation.scale = nil 75 | settings.animation.present.duration = 0.5 76 | settings.animation.present.options = [.curveEaseOut, .allowUserInteraction] 77 | settings.animation.present.springVelocity = 0.0 78 | settings.animation.present.damping = 0.7 79 | settings.statusBar.style = .default 80 | 81 | onConfigureCellForAction = { cell, action, indexPath in 82 | cell.actionTitleLabel.text = action.data 83 | cell.actionTitleLabel.textColor = .white 84 | cell.alpha = action.enabled ? 1.0 : 0.5 85 | } 86 | } 87 | 88 | required public init?(coder aDecoder: NSCoder) { 89 | super.init(coder: aDecoder) 90 | } 91 | 92 | open override func viewDidLoad() { 93 | super.viewDidLoad() 94 | 95 | let width = collectionView.bounds.width - safeAreaInsets.left - safeAreaInsets.right 96 | let height = contentHeight + topSpace + SkypeActionController.bottomPadding + safeAreaInsets.bottom 97 | contextView = ContextView(frame: CGRect(x: 0, y: -topSpace, width: width, height: height)) 98 | contextView.animatedBackgroundColor = backgroundColor; 99 | contextView.autoresizingMask = [.flexibleWidth, .flexibleBottomMargin] 100 | 101 | collectionView.clipsToBounds = false 102 | collectionView.addSubview(contextView) 103 | collectionView.sendSubviewToBack(contextView) 104 | 105 | normalAnimationRect = UIView(frame: CGRect(x: 0, y: view.bounds.height / 2, width: 30, height: 30)) 106 | normalAnimationRect.isHidden = true 107 | view.addSubview(normalAnimationRect) 108 | 109 | springAnimationRect = UIView(frame: CGRect(x: 40, y: view.bounds.height / 2, width: 30, height: 30)) 110 | springAnimationRect.isHidden = true 111 | view.addSubview(springAnimationRect) 112 | 113 | backgroundView.backgroundColor = UIColor.black.withAlphaComponent(0.65) 114 | } 115 | 116 | @available(iOS 11, *) 117 | override open func viewSafeAreaInsetsDidChange() { 118 | super.viewSafeAreaInsetsDidChange() 119 | contextView.frame.size.height = contentHeight + topSpace + SkypeActionController.bottomPadding + safeAreaInsets.bottom 120 | contextView.frame.size.width = collectionView.bounds.width - safeAreaInsets.left - safeAreaInsets.right 121 | } 122 | 123 | override open func onWillPresentView() { 124 | super.onWillPresentView() 125 | 126 | collectionView.frame.origin.y = contentHeight + (topSpace - contextView.topSpace) 127 | 128 | startAnimation() 129 | let initSpace = CGFloat(45.0) 130 | let initTime = 0.1 131 | let animationDuration = settings.animation.present.duration - 0.1 132 | 133 | let options: UIView.AnimationOptions = [.curveEaseOut, .allowUserInteraction] 134 | UIView.animate(withDuration: initTime, delay: settings.animation.present.delay, options: options, animations: { [weak self] in 135 | guard let me = self else { 136 | return 137 | } 138 | 139 | var frame = me.springAnimationRect.frame 140 | frame.origin.y = frame.origin.y - initSpace 141 | me.springAnimationRect.frame = frame 142 | }, completion: { [weak self] finished in 143 | guard let me = self , finished else { 144 | self?.finishAnimation() 145 | return 146 | } 147 | 148 | UIView.animate(withDuration: animationDuration - initTime, delay: 0, options: options, animations: { [weak self] in 149 | guard let me = self else { 150 | return 151 | } 152 | 153 | var frame = me.springAnimationRect.frame 154 | frame.origin.y -= (me.contentHeight - initSpace) 155 | me.springAnimationRect.frame = frame 156 | }, completion: { (finish) -> Void in 157 | me.finishAnimation() 158 | }) 159 | }) 160 | 161 | 162 | UIView.animate(withDuration: animationDuration - initTime, delay: settings.animation.present.delay + initTime, options: options, animations: { [weak self] in 163 | guard let me = self else { 164 | return 165 | } 166 | 167 | var frame = me.normalAnimationRect.frame 168 | frame.origin.y -= me.contentHeight 169 | me.normalAnimationRect.frame = frame 170 | }, completion:nil) 171 | } 172 | 173 | 174 | override open func dismissView(_ presentedView: UIView, presentingView: UIView, animationDuration: Double, completion: ((_ completed: Bool) -> Void)?) { 175 | finishAnimation() 176 | finishAnimation() 177 | 178 | let animationSettings = settings.animation.dismiss 179 | UIView.animate(withDuration: animationDuration, 180 | delay: animationSettings.delay, 181 | usingSpringWithDamping: animationSettings.damping, 182 | initialSpringVelocity: animationSettings.springVelocity, 183 | options: animationSettings.options, 184 | animations: { [weak self] in 185 | self?.backgroundView.alpha = 0.0 186 | }, 187 | completion:nil) 188 | 189 | gravityBehavior.action = { [weak self] in 190 | if let me = self { 191 | let progress = min(1.0, me.collectionView.frame.origin.y / (me.contentHeight + (me.topSpace - me.contextView.topSpace))) 192 | let pixels = min(20, progress * 150.0) 193 | me.contextView.diff = -pixels 194 | me.contextView.setNeedsDisplay() 195 | 196 | if me.collectionView.frame.origin.y > me.view.bounds.size.height { 197 | self?.animator.removeAllBehaviors() 198 | completion?(true) 199 | } 200 | } 201 | } 202 | animator.addBehavior(gravityBehavior) 203 | } 204 | 205 | // MARK: - Private Helpers 206 | 207 | fileprivate var diff = CGFloat(0) 208 | fileprivate var displayLink: CADisplayLink! 209 | fileprivate var animationCount = 0 210 | 211 | fileprivate lazy var animator: UIDynamicAnimator = { [unowned self] in 212 | let animator = UIDynamicAnimator(referenceView: self.view) 213 | return animator 214 | }() 215 | 216 | fileprivate lazy var gravityBehavior: UIGravityBehavior = { [unowned self] in 217 | let gravityBehavior = UIGravityBehavior(items: [self.collectionView]) 218 | gravityBehavior.magnitude = 2.0 219 | return gravityBehavior 220 | }() 221 | 222 | @objc fileprivate func update(_ displayLink: CADisplayLink) { 223 | let normalRectLayer = normalAnimationRect.layer.presentation() 224 | let springRectLayer = springAnimationRect.layer.presentation() 225 | 226 | guard let normalRectFrame = normalRectLayer?.frame, 227 | let springRectFrame = springRectLayer?.frame else { 228 | return 229 | } 230 | contextView.diff = normalRectFrame.origin.y - springRectFrame.origin.y 231 | contextView.setNeedsDisplay() 232 | } 233 | 234 | fileprivate func startAnimation() { 235 | if displayLink == nil { 236 | self.displayLink = CADisplayLink(target: self, selector: #selector(SkypeActionController.update(_:))) 237 | self.displayLink.add(to: RunLoop.main, forMode: RunLoop.Mode.default) 238 | } 239 | animationCount += 1 240 | } 241 | 242 | fileprivate func finishAnimation() { 243 | animationCount -= 1 244 | if animationCount == 0 { 245 | displayLink.invalidate() 246 | displayLink = nil 247 | } 248 | } 249 | 250 | fileprivate class ContextView: UIView { 251 | let topSpace = CGFloat(25) 252 | var diff = CGFloat(0) 253 | var animatedBackgroundColor: UIColor! 254 | 255 | override init(frame: CGRect) { 256 | super.init(frame: frame) 257 | backgroundColor = .clear 258 | } 259 | 260 | required init?(coder aDecoder: NSCoder) { 261 | fatalError("init(coder:) has not been implemented") 262 | } 263 | 264 | override func draw(_ rect: CGRect) { 265 | let path = UIBezierPath() 266 | 267 | path.move(to: CGPoint(x: 0, y: frame.height)) 268 | path.addLine(to: CGPoint(x: frame.width, y: frame.height)) 269 | path.addLine(to: CGPoint(x: frame.width, y: topSpace)) 270 | path.addQuadCurve(to: CGPoint(x: 0, y: topSpace), controlPoint: CGPoint(x: frame.width/2, y: topSpace - diff)) 271 | path.close() 272 | 273 | guard let context = UIGraphicsGetCurrentContext() else { 274 | return 275 | } 276 | context.addPath(path.cgPath) 277 | animatedBackgroundColor.set() 278 | context.fillPath() 279 | } 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /Example/CustomActionControllers/Skype/SkypeCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Example/CustomActionControllers/Spotify/Spotify.swift: -------------------------------------------------------------------------------- 1 | // Spotify.swift 2 | // Spotify ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | #if IMPORT_BASE_XLACTIONCONTROLLER 27 | import XLActionController 28 | #endif 29 | 30 | open class SpotifyCell: ActionCell { 31 | 32 | public override init(frame: CGRect) { 33 | super.init(frame: frame) 34 | initialize() 35 | } 36 | 37 | required public init?(coder aDecoder: NSCoder) { 38 | super.init(coder: aDecoder) 39 | } 40 | 41 | open override func awakeFromNib() { 42 | super.awakeFromNib() 43 | initialize() 44 | } 45 | 46 | func initialize() { 47 | backgroundColor = .clear 48 | let backgroundView = UIView() 49 | backgroundView.backgroundColor = UIColor.white.withAlphaComponent(0.3) 50 | selectedBackgroundView = backgroundView 51 | actionTitleLabel?.textColor = .white 52 | actionTitleLabel?.textAlignment = .left 53 | 54 | } 55 | } 56 | 57 | public struct SpotifyHeaderData { 58 | 59 | var title: String 60 | var subtitle: String 61 | var image: UIImage 62 | 63 | public init(title: String, subtitle: String, image: UIImage) { 64 | self.title = title 65 | self.subtitle = subtitle 66 | self.image = image 67 | } 68 | } 69 | 70 | open class SpotifyHeaderView: UICollectionReusableView { 71 | 72 | open lazy var imageView: UIImageView = { 73 | let imageView = UIImageView(frame: CGRect.zero) 74 | imageView.image = UIImage(named: "sp-header-icon") 75 | imageView.translatesAutoresizingMaskIntoConstraints = false 76 | return imageView 77 | }() 78 | 79 | open lazy var title: UILabel = { 80 | let title = UILabel(frame: CGRect.zero) 81 | title.font = UIFont(name: "HelveticaNeue-Bold", size: 18) 82 | title.text = "The Fast And ... The Furious Soundtrack Collection" 83 | title.textColor = UIColor.white 84 | title.translatesAutoresizingMaskIntoConstraints = false 85 | title.sizeToFit() 86 | return title 87 | }() 88 | 89 | open lazy var artist: UILabel = { 90 | let discArtist = UILabel(frame: CGRect.zero) 91 | discArtist.font = UIFont(name: "HelveticaNeue", size: 16) 92 | discArtist.text = "Various..." 93 | discArtist.textColor = UIColor.white.withAlphaComponent(0.8) 94 | discArtist.translatesAutoresizingMaskIntoConstraints = false 95 | discArtist.sizeToFit() 96 | return discArtist 97 | }() 98 | 99 | public override init(frame: CGRect) { 100 | super.init(frame: frame) 101 | initialize() 102 | } 103 | 104 | required public init?(coder aDecoder: NSCoder) { 105 | super.init(coder: aDecoder) 106 | } 107 | 108 | open override func awakeFromNib() { 109 | super.awakeFromNib() 110 | initialize() 111 | } 112 | 113 | func initialize() { 114 | translatesAutoresizingMaskIntoConstraints = false 115 | backgroundColor = .clear 116 | addSubview(imageView) 117 | addSubview(title) 118 | addSubview(artist) 119 | let separator: UIView = { 120 | let separator = UIView(frame: CGRect.zero) 121 | separator.backgroundColor = UIColor.white.withAlphaComponent(0.3) 122 | separator.translatesAutoresizingMaskIntoConstraints = false 123 | return separator 124 | }() 125 | addSubview(separator) 126 | 127 | let views = [ "ico": imageView, "title": title, "artist": artist, "separator": separator ] 128 | let metrics = [ "icow": 54, "icoh": 54 ] 129 | let options = NSLayoutConstraint.FormatOptions() 130 | 131 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-15-[ico(icow)]-10-[title]-15-|", options: options, metrics: metrics, views: views)) 132 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[separator]|", options: options, metrics: metrics, views: views)) 133 | 134 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-10-[ico(icoh)]", options: options, metrics: metrics, views: views)) 135 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-18-[title][artist]", options: .alignAllLeft, metrics: metrics, views: views)) 136 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[separator(1)]|", options: options, metrics: metrics, views: views)) 137 | } 138 | } 139 | 140 | open class SpotifyActionController: ActionController { 141 | 142 | fileprivate lazy var blurView: UIVisualEffectView = { 143 | let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .dark)) 144 | blurView.autoresizingMask = [.flexibleHeight, .flexibleWidth] 145 | return blurView 146 | }() 147 | 148 | open override func viewDidLoad() { 149 | super.viewDidLoad() 150 | backgroundView.addSubview(blurView) 151 | 152 | cancelView?.frame.origin.y = view.bounds.size.height // Starts hidden below screen 153 | cancelView?.layer.shadowColor = UIColor.black.cgColor 154 | cancelView?.layer.shadowOffset = CGSize( width: 0, height: -4) 155 | cancelView?.layer.shadowRadius = 2 156 | cancelView?.layer.shadowOpacity = 0.8 157 | } 158 | 159 | open override func viewWillAppear(_ animated: Bool) { 160 | super.viewWillAppear(animated) 161 | blurView.frame = backgroundView.bounds 162 | } 163 | 164 | public override init(nibName nibNameOrNil: String? = nil, bundle nibBundleOrNil: Bundle? = nil) { 165 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 166 | settings.behavior.bounces = true 167 | settings.behavior.scrollEnabled = true 168 | settings.cancelView.showCancel = true 169 | settings.animation.scale = nil 170 | settings.animation.present.springVelocity = 0.0 171 | settings.cancelView.hideCollectionViewBehindCancelView = true 172 | 173 | cellSpec = .nibFile(nibName: "SpotifyCell", bundle: Bundle(for: SpotifyCell.self), height: { _ in 60 }) 174 | headerSpec = .cellClass( height: { _ in 84 }) 175 | 176 | onConfigureCellForAction = { [weak self] cell, action, indexPath in 177 | cell.setup(action.data?.title, detail: action.data?.subtitle, image: action.data?.image) 178 | cell.separatorView?.isHidden = indexPath.item == (self?.collectionView.numberOfItems(inSection: indexPath.section))! - 1 179 | cell.alpha = action.enabled ? 1.0 : 0.5 180 | } 181 | onConfigureHeader = { (header: SpotifyHeaderView, data: SpotifyHeaderData) in 182 | header.title.text = data.title 183 | header.artist.text = data.subtitle 184 | header.imageView.image = data.image 185 | } 186 | } 187 | 188 | required public init?(coder aDecoder: NSCoder) { 189 | super.init(coder: aDecoder) 190 | } 191 | 192 | open override func performCustomDismissingAnimation(_ presentedView: UIView, presentingView: UIView) { 193 | super.performCustomDismissingAnimation(presentedView, presentingView: presentingView) 194 | cancelView?.frame.origin.y = view.bounds.size.height + 10 195 | } 196 | 197 | open override func onWillPresentView() { 198 | cancelView?.frame.origin.y = view.bounds.size.height 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /Example/CustomActionControllers/Spotify/SpotifyCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | HelveticaNeue 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /Example/CustomActionControllers/Tweetbot/Tweetbot.swift: -------------------------------------------------------------------------------- 1 | // Tweetbot.swift 2 | // Tweetbot ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | #if IMPORT_BASE_XLACTIONCONTROLLER 27 | import XLActionController 28 | #endif 29 | 30 | open class TweetbotCell: ActionCell { 31 | 32 | public override init(frame: CGRect) { 33 | super.init(frame: frame) 34 | initialize() 35 | } 36 | 37 | required public init?(coder aDecoder: NSCoder) { 38 | super.init(coder: aDecoder) 39 | } 40 | 41 | open override func awakeFromNib() { 42 | super.awakeFromNib() 43 | initialize() 44 | } 45 | 46 | func initialize() { 47 | actionTitleLabel?.font = UIFont(name: "HelveticaNeue-Bold", size: 18) 48 | actionTitleLabel?.textColor = .white 49 | actionTitleLabel?.textAlignment = .center 50 | backgroundColor = .darkGray 51 | let backgroundView = UIView() 52 | backgroundView.backgroundColor = UIColor(red: 0.31, green: 0.42, blue: 0.54, alpha: 1.0) 53 | selectedBackgroundView = backgroundView 54 | } 55 | } 56 | 57 | open class TweetbotActionController: DynamicsActionController { 58 | 59 | public override init(nibName nibNameOrNil: String? = nil, bundle nibBundleOrNil: Bundle? = nil) { 60 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 61 | backgroundView.backgroundColor = UIColor.black.withAlphaComponent(0.5) 62 | settings.animation.present.duration = 0.5 63 | settings.animation.dismiss.duration = 0.5 64 | settings.behavior.bounces = true 65 | settings.behavior.useDynamics = true 66 | collectionView.contentInset = UIEdgeInsets(top: 0.0, left: 12.0, bottom: 6.0, right: 12.0) 67 | 68 | cellSpec = .nibFile(nibName: "TweetbotCell", bundle: Bundle(for: TweetbotCell.self), height: { _ in 50 }) 69 | 70 | onConfigureCellForAction = { [weak self] cell, action, indexPath in 71 | 72 | cell.setup(action.data, detail: nil, image: nil) 73 | let actions = self?.sectionForIndex(indexPath.section)?.actions 74 | let actionsCount = actions!.count 75 | cell.separatorView?.isHidden = indexPath.item == (self?.collectionView.numberOfItems(inSection: indexPath.section))! - 1 76 | cell.backgroundColor = action.style == .cancel ? UIColor(white: 0.23, alpha: 1.0) : .darkGray 77 | cell.alpha = action.enabled ? 1.0 : 0.5 78 | 79 | var corners = UIRectCorner() 80 | if indexPath.item == 0 { 81 | corners = [.topLeft, .topRight] 82 | } 83 | if indexPath.item == actionsCount - 1 { 84 | corners = corners.union([.bottomLeft, .bottomRight]) 85 | } 86 | 87 | if corners == .allCorners { 88 | cell.layer.mask = nil 89 | cell.layer.cornerRadius = 8.0 90 | } else { 91 | let borderMask = CAShapeLayer() 92 | borderMask.frame = cell.bounds 93 | borderMask.path = UIBezierPath(roundedRect: cell.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: 8.0, height: 8.0)).cgPath 94 | cell.layer.mask = borderMask 95 | } 96 | } 97 | } 98 | 99 | required public init?(coder aDecoder: NSCoder) { 100 | super.init(coder: aDecoder) 101 | } 102 | 103 | // MARK: - UICollectionViewDelegateFlowLayout 104 | 105 | open override func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { 106 | return UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 0.0) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Example/CustomActionControllers/Tweetbot/TweetbotCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Example/CustomActionControllers/Twitter/Twitter.swift: -------------------------------------------------------------------------------- 1 | // Twitter.swift 2 | // Twitter ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | #if IMPORT_BASE_XLACTIONCONTROLLER 27 | import XLActionController 28 | #endif 29 | 30 | open class TwitterCell: ActionCell { 31 | 32 | public override init(frame: CGRect) { 33 | super.init(frame: frame) 34 | initialize() 35 | } 36 | 37 | required public init?(coder aDecoder: NSCoder) { 38 | super.init(coder: aDecoder) 39 | } 40 | 41 | open override func awakeFromNib() { 42 | super.awakeFromNib() 43 | initialize() 44 | } 45 | 46 | func initialize() { 47 | backgroundColor = .white 48 | actionImageView?.clipsToBounds = true 49 | actionImageView?.layer.cornerRadius = 5.0 50 | let backgroundView = UIView() 51 | backgroundView.backgroundColor = UIColor(white: 0.0, alpha: 0.15) 52 | selectedBackgroundView = backgroundView 53 | } 54 | } 55 | 56 | open class TwitterActionControllerHeader: UICollectionReusableView { 57 | 58 | lazy var label: UILabel = { 59 | let label = UILabel() 60 | label.translatesAutoresizingMaskIntoConstraints = false 61 | label.textAlignment = .center 62 | label.backgroundColor = .white 63 | label.font = UIFont.boldSystemFont(ofSize: 17) 64 | return label 65 | }() 66 | 67 | lazy var bottomLine: UIView = { 68 | let bottomLine = UIView() 69 | bottomLine.translatesAutoresizingMaskIntoConstraints = false 70 | bottomLine.backgroundColor = .lightGray 71 | return bottomLine 72 | }() 73 | 74 | override init(frame: CGRect) { 75 | super.init(frame: frame) 76 | backgroundColor = .white 77 | addSubview(label) 78 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[label]|", options: NSLayoutConstraint.FormatOptions(), metrics: nil, views: ["label": label])) 79 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[label]|", options: NSLayoutConstraint.FormatOptions(), metrics: nil, views: ["label": label])) 80 | addSubview(bottomLine) 81 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[line(1)]|", options: NSLayoutConstraint.FormatOptions(), metrics: nil, views: ["line": bottomLine])) 82 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[line]|", options: NSLayoutConstraint.FormatOptions(), metrics: nil, views: ["line": bottomLine])) 83 | } 84 | 85 | required public init?(coder aDecoder: NSCoder) { 86 | super.init(coder: aDecoder) 87 | } 88 | } 89 | 90 | 91 | open class TwitterActionController: ActionController { 92 | 93 | static let bottomPadding: CGFloat = 20.0 94 | 95 | lazy var hideBottomSpaceView: UIView = { 96 | let width = collectionView.bounds.width - safeAreaInsets.left - safeAreaInsets.right 97 | let height = contentHeight + TwitterActionController.bottomPadding + safeAreaInsets.bottom 98 | let hideBottomSpaceView = UIView(frame: CGRect.init(x: 0, y: 0, width: width, height: height)) 99 | hideBottomSpaceView.autoresizingMask = [.flexibleWidth, .flexibleBottomMargin] 100 | hideBottomSpaceView.backgroundColor = .white 101 | return hideBottomSpaceView 102 | }() 103 | 104 | public override init(nibName nibNameOrNil: String? = nil, bundle nibBundleOrNil: Bundle? = nil) { 105 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 106 | settings.animation.present.duration = 0.6 107 | settings.animation.dismiss.duration = 0.6 108 | cellSpec = CellSpec.nibFile(nibName: "TwitterCell", bundle: Bundle(for: TwitterCell.self), height: { _ in 56 }) 109 | headerSpec = .cellClass(height: { _ -> CGFloat in return 45 }) 110 | 111 | onConfigureHeader = { header, title in 112 | header.label.text = title 113 | } 114 | onConfigureCellForAction = { [weak self] cell, action, indexPath in 115 | cell.setup(action.data?.title, detail: action.data?.subtitle, image: action.data?.image) 116 | cell.separatorView?.isHidden = indexPath.item == (self?.collectionView.numberOfItems(inSection: indexPath.section))! - 1 117 | cell.alpha = action.enabled ? 1.0 : 0.5 118 | } 119 | } 120 | 121 | required public init?(coder aDecoder: NSCoder) { 122 | fatalError("init(coder:) has not been implemented") 123 | } 124 | 125 | open override func viewDidLoad() { 126 | super.viewDidLoad() 127 | 128 | collectionView.clipsToBounds = false 129 | collectionView.addSubview(hideBottomSpaceView) 130 | collectionView.sendSubviewToBack(hideBottomSpaceView) 131 | } 132 | 133 | @available(iOS 11, *) 134 | override open func viewSafeAreaInsetsDidChange() { 135 | super.viewSafeAreaInsetsDidChange() 136 | hideBottomSpaceView.frame.size.height = contentHeight + TwitterActionController.bottomPadding + safeAreaInsets.bottom 137 | hideBottomSpaceView.frame.size.width = collectionView.bounds.width - safeAreaInsets.left - safeAreaInsets.right 138 | } 139 | 140 | override open func dismissView(_ presentedView: UIView, presentingView: UIView, animationDuration: Double, completion: ((_ completed: Bool) -> Void)?) { 141 | onWillDismissView() 142 | let animationSettings = settings.animation.dismiss 143 | let upTime = 0.1 144 | UIView.animate(withDuration: upTime, delay: 0, options: .curveEaseIn, animations: { [weak self] in 145 | self?.collectionView.frame.origin.y -= 10 146 | }, completion: { [weak self] (completed) -> Void in 147 | UIView.animate(withDuration: animationDuration - upTime, 148 | delay: 0, 149 | usingSpringWithDamping: animationSettings.damping, 150 | initialSpringVelocity: animationSettings.springVelocity, 151 | options: UIView.AnimationOptions.curveEaseIn, 152 | animations: { [weak self] in 153 | presentingView.transform = CGAffineTransform.identity 154 | self?.performCustomDismissingAnimation(presentedView, presentingView: presentingView) 155 | }, 156 | completion: { [weak self] finished in 157 | self?.onDidDismissView() 158 | completion?(finished) 159 | }) 160 | }) 161 | } 162 | } 163 | 164 | -------------------------------------------------------------------------------- /Example/CustomActionControllers/Twitter/TwitterCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 39 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /Example/CustomActionControllers/Youtube/Youtube.swift: -------------------------------------------------------------------------------- 1 | // Youtube.swift 2 | // Youtube ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | #if IMPORT_BASE_XLACTIONCONTROLLER 27 | import XLActionController 28 | #endif 29 | 30 | open class YoutubeCell: ActionCell { 31 | 32 | open lazy var animatableBackgroundView: UIView = { [weak self] in 33 | let view = UIView(frame: self?.frame ?? CGRect.zero) 34 | view.backgroundColor = UIColor.red.withAlphaComponent(0.40) 35 | return view 36 | }() 37 | 38 | public override init(frame: CGRect) { 39 | super.init(frame: frame) 40 | initialize() 41 | } 42 | 43 | required public init?(coder aDecoder: NSCoder) { 44 | super.init(coder: aDecoder) 45 | } 46 | 47 | open override func awakeFromNib() { 48 | super.awakeFromNib() 49 | initialize() 50 | } 51 | 52 | func initialize() { 53 | actionTitleLabel?.textColor = UIColor(white: 0.098, alpha: 1.0) 54 | let backgroundView = UIView() 55 | backgroundView.backgroundColor = UIColor.black.withAlphaComponent(0.0) 56 | backgroundView.addSubview(animatableBackgroundView) 57 | selectedBackgroundView = backgroundView 58 | } 59 | 60 | open override var isHighlighted: Bool { 61 | didSet { 62 | if isHighlighted { 63 | animatableBackgroundView.backgroundColor = UIColor.black.withAlphaComponent(0.0) 64 | animatableBackgroundView.frame = CGRect(x: 0, y: 0, width: 30, height: frame.height) 65 | animatableBackgroundView.center = CGPoint(x: frame.width * 0.5, y: frame.height * 0.5) 66 | 67 | UIView.animate(withDuration: 0.5) { [weak self] in 68 | guard let me = self else { 69 | return 70 | } 71 | 72 | me.animatableBackgroundView.frame = CGRect(x: 0, y: 0, width: me.frame.width, height: me.frame.height) 73 | me.animatableBackgroundView.backgroundColor = UIColor.black.withAlphaComponent(0.08) 74 | } 75 | } else { 76 | animatableBackgroundView.backgroundColor = animatableBackgroundView.backgroundColor?.withAlphaComponent(0.0) 77 | } 78 | } 79 | } 80 | } 81 | 82 | open class YoutubeActionController: ActionController { 83 | 84 | public override init(nibName nibNameOrNil: String? = nil, bundle nibBundleOrNil: Bundle? = nil) { 85 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 86 | 87 | collectionViewLayout.minimumLineSpacing = -0.5 88 | 89 | settings.behavior.hideOnScrollDown = false 90 | settings.animation.scale = nil 91 | settings.animation.present.duration = 0.6 92 | settings.animation.dismiss.duration = 0.6 93 | settings.animation.dismiss.offset = 30 94 | settings.animation.dismiss.options = .curveLinear 95 | 96 | cellSpec = .nibFile(nibName: "YoutubeCell", bundle: Bundle(for: YoutubeCell.self), height: { _ in 46 }) 97 | 98 | onConfigureCellForAction = { cell, action, indexPath in 99 | cell.setup(action.data?.title, detail: action.data?.subtitle, image: action.data?.image) 100 | cell.alpha = action.enabled ? 1.0 : 0.5 101 | } 102 | } 103 | 104 | required public init?(coder aDecoder: NSCoder) { 105 | fatalError("init(coder:) has not been implemented") 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Example/CustomActionControllers/Youtube/YoutubeCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | XLActionController 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 5.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Example/MainViewController.swift: -------------------------------------------------------------------------------- 1 | // MainViewController.swift 2 | // MainViewController ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | 27 | class MainViewController: UITableViewController { 28 | 29 | override func viewDidLoad() { 30 | super.viewDidLoad() 31 | 32 | navigationItem.title = "XLActionController's Examples" 33 | } 34 | 35 | override func viewWillAppear(_ animated: Bool) { 36 | super.viewWillAppear(animated) 37 | navigationController?.setNavigationBarHidden(false, animated: animated) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Example/PeriscopeExampleViewController.swift: -------------------------------------------------------------------------------- 1 | // PeriscopeExampleViewController.swift 2 | // XLActionController ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | import XLActionController 27 | 28 | class PeriscopeExampleViewController: UIViewController { 29 | 30 | override func viewWillAppear(_ animated: Bool) { 31 | super.viewWillAppear(animated) 32 | navigationController?.setNavigationBarHidden(true, animated: animated) 33 | } 34 | 35 | override var preferredStatusBarStyle : UIStatusBarStyle { 36 | return .lightContent 37 | } 38 | 39 | @IBAction func backButtonDidTouch(_ sender: UIButton) { 40 | _ = self.navigationController?.popViewController(animated: true) 41 | } 42 | 43 | @IBAction func tapGestureDidRecognize(_ sender: UITapGestureRecognizer) { 44 | let actionController = PeriscopeActionController() 45 | actionController.headerData = "Are you sure you want to block?" 46 | actionController.addAction(Action("Block user", style: .destructive, handler: { action in 47 | })) 48 | actionController.addSection(PeriscopeSection()) 49 | actionController.addAction(Action("Cancel", style: .cancel, handler: { action in 50 | })) 51 | present(actionController, animated: true, completion: nil) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Example/SkypeExampleViewController.swift: -------------------------------------------------------------------------------- 1 | // SkypeExampleViewController.swift 2 | // XLActionController ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | import XLActionController 27 | 28 | class SkypeExampleViewController: UIViewController { 29 | 30 | override func viewWillAppear(_ animated: Bool) { 31 | super.viewWillAppear(animated) 32 | navigationController?.setNavigationBarHidden(true, animated: animated) 33 | } 34 | 35 | @IBAction func backButtonDidTouch(_ sender: UIButton) { 36 | _ = navigationController?.popViewController(animated: true) 37 | } 38 | 39 | @IBAction func tapGestureDidRecognize(_ sender: UITapGestureRecognizer) { 40 | let actionController = SkypeActionController() 41 | actionController.addAction(Action("Take photo", style: .default, handler: { action in 42 | })) 43 | actionController.addAction(Action("Choose existing photo", style: .default, handler: { action in 44 | })) 45 | actionController.addAction(Action("Remove profile picture", style: .default, handler: { action in 46 | })) 47 | actionController.addAction(Action("Cancel", style: .cancel, handler: nil)) 48 | 49 | present(actionController, animated: true, completion: nil) 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Example/SpotifyExampleViewController.swift: -------------------------------------------------------------------------------- 1 | // SpotifyExampleViewController.swift 2 | // XLActionController ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | import XLActionController 27 | 28 | class SpotifyExampleViewController: UIViewController { 29 | 30 | override func viewWillAppear(_ animated: Bool) { 31 | super.viewWillAppear(animated) 32 | navigationController?.setNavigationBarHidden(true, animated: animated) 33 | } 34 | 35 | override func viewDidLoad() { 36 | navigationController?.setNavigationBarHidden(true, animated: false) 37 | } 38 | 39 | override var preferredStatusBarStyle : UIStatusBarStyle { 40 | return .lightContent 41 | } 42 | 43 | @IBAction func backButtonDidTouch(_ sender: UIButton) { 44 | _ = navigationController?.popViewController(animated: true) 45 | } 46 | 47 | @IBAction func tapGestureDidRecognize(_ sender: UITapGestureRecognizer) { 48 | let actionController = SpotifyActionController() 49 | actionController.headerData = SpotifyHeaderData(title: "The Fast And The Furious Soundtrack Collection", subtitle: "Various Artists", image: UIImage(named: "sp-header-icon")!) 50 | actionController.addAction(Action(ActionData(title: "Save Full Album", image: UIImage(named: "sp-add-icon")!), style: .default, handler: { action in })) 51 | actionController.addAction(Action(ActionData(title: "Remove", image: UIImage(named: "sp-remove-icon")!), style: .default, handler: { action in })) 52 | actionController.addAction(Action(ActionData(title: "Share", image: UIImage(named: "sp-share-icon")!), style: .default, handler: { action in })) 53 | actionController.addAction(Action(ActionData(title: "Go to Album", image: UIImage(named: "sp-view-album-icon")!), style: .default, handler: { action in })) 54 | actionController.addAction(Action(ActionData(title: "Start radio", image: UIImage(named: "sp-radio-icon")!), style: .default, handler: { action in })) 55 | 56 | 57 | present(actionController, animated: true, completion: nil) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Example/TweetbotExampleViewController.swift: -------------------------------------------------------------------------------- 1 | // TweetBotExampleViewController.swift 2 | // XLActionController ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | import XLActionController 27 | 28 | class TweetBotExampleViewController: UIViewController { 29 | 30 | override func viewWillAppear(_ animated: Bool) { 31 | super.viewWillAppear(animated) 32 | navigationController?.setNavigationBarHidden(true, animated: animated) 33 | } 34 | 35 | override var preferredStatusBarStyle : UIStatusBarStyle { 36 | return .lightContent 37 | } 38 | 39 | @IBAction func backButtonDidTouch(_ sender: UIButton) { 40 | _ = navigationController?.popViewController(animated: true) 41 | } 42 | 43 | @IBAction func tapGestureDidRecognize(_ sender: UITapGestureRecognizer) { 44 | let actionController = TweetbotActionController() 45 | 46 | actionController.addAction(Action("View Details", style: .default, handler: { action in 47 | })) 48 | actionController.addAction(Action("View Retweets", style: .default, handler: { action in 49 | })) 50 | actionController.addAction(Action("View in Favstar", style: .default, handler: { action in 51 | })) 52 | actionController.addAction(Action("Translate", style: .default, executeImmediatelyOnTouch: true, handler: { action in 53 | })) 54 | actionController.addSection(Section()) 55 | actionController.addAction(Action("Cancel", style: .cancel, handler:nil)) 56 | 57 | present(actionController, animated: true, completion: nil) 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /Example/TwitterExampleViewController.swift: -------------------------------------------------------------------------------- 1 | // TwitterExampleViewController.swift 2 | // XLActionController ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | import XLActionController 27 | 28 | class TwitterExampleViewController: UIViewController { 29 | 30 | override func viewWillAppear(_ animated: Bool) { 31 | super.viewWillAppear(animated) 32 | navigationController?.setNavigationBarHidden(true, animated: animated) 33 | } 34 | 35 | override var preferredStatusBarStyle : UIStatusBarStyle { 36 | return .lightContent 37 | } 38 | 39 | @IBAction func backButtonDidTouch(_ sender: UIButton) { 40 | _ = navigationController?.popViewController(animated: true) 41 | } 42 | 43 | @IBAction func tapGestureDidRecognize(_ sender: UITapGestureRecognizer) { 44 | let actionController = TwitterActionController() 45 | actionController.addAction(Action(ActionData(title: "Xmartlabs", subtitle: "@xmartlabs", image: UIImage(named: "tw-xmartlabs")!), style: .default, handler: { action in 46 | })) 47 | actionController.addAction(Action(ActionData(title: "Miguel", subtitle: "@remer88", image: UIImage(named: "tw-remer")!), style: .default, handler: { action in 48 | })) 49 | actionController.headerData = "Accounts" 50 | present(actionController, animated: true, completion: nil) 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Example/UITests/ExampleUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleUITests.swift 3 | // ExampleUITests 4 | // 5 | // Created by Martin Barreto on 11/16/15. 6 | // Copyright © 2015 Xmartlabs. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class ExampleUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | 18 | // In UI tests it is usually best to stop immediately when a failure occurs. 19 | continueAfterFailure = false 20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 21 | XCUIApplication().launch() 22 | 23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testExample() { 32 | // Use recording to get started writing UI tests. 33 | // Use XCTAssert and related functions to verify your tests produce the correct results. 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Example/UITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Example/YouTubeExampleViewController.swift: -------------------------------------------------------------------------------- 1 | // YouTubeExampleViewController.swift 2 | // XLActionController ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | import XLActionController 27 | 28 | class YouTubeExampleViewController: UIViewController { 29 | 30 | override func viewWillAppear(_ animated: Bool) { 31 | super.viewWillAppear(animated) 32 | navigationController?.setNavigationBarHidden(true, animated: animated) 33 | } 34 | 35 | @IBAction func backButtonDidTouch(_ sender: UIButton) { 36 | _ = navigationController?.popViewController(animated: true) 37 | } 38 | 39 | @IBAction func tapGestureDidRecognize(_ sender: UITapGestureRecognizer) { 40 | 41 | let actionController = YoutubeActionController() 42 | 43 | actionController.addAction(Action(ActionData(title: "Add to Watch Later", image: UIImage(named: "yt-add-to-watch-later-icon")!), style: .default, handler: { action in 44 | })) 45 | actionController.addAction(Action(ActionData(title: "Add to Playlist...", image: UIImage(named: "yt-add-to-playlist-icon")!), style: .default, handler: { action in 46 | })) 47 | actionController.addAction(Action(ActionData(title: "Share...", image: UIImage(named: "yt-share-icon")!), style: .default, handler: { action in 48 | })) 49 | actionController.addAction(Action(ActionData(title: "Cancel", image: UIImage(named: "yt-cancel-icon")!), style: .cancel, handler: nil)) 50 | 51 | present(actionController, animated: true, completion: nil) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 XMARTLABS (http://xmartlabs.com) 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 | -------------------------------------------------------------------------------- /Media/demo_periscope.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Media/demo_periscope.gif -------------------------------------------------------------------------------- /Media/demo_skype.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Media/demo_skype.gif -------------------------------------------------------------------------------- /Media/demo_spotify.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Media/demo_spotify.gif -------------------------------------------------------------------------------- /Media/demo_tweetbot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Media/demo_tweetbot.gif -------------------------------------------------------------------------------- /Media/demo_twitter.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Media/demo_twitter.gif -------------------------------------------------------------------------------- /Media/demo_youtube.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/Media/demo_youtube.gif -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | 3 | import PackageDescription 4 | 5 | func getExampleTarget(name: String) -> Target { 6 | return .target(name: "XLActionController_" + name, 7 | dependencies: [Target.Dependency.target(name: "XLActionController")], 8 | path: "Example/CustomActionControllers/\(name)", 9 | sources: ["\(name).swift"], 10 | resources: [Resource.process("\(name)Cell.xib")], 11 | swiftSettings: [SwiftSetting.define("IMPORT_BASE_XLACTIONCONTROLLER")]) 12 | } 13 | 14 | let package = Package( 15 | name: "XLActionController", 16 | platforms: [ 17 | .iOS(.v9) 18 | ], 19 | products: [ 20 | .library(name: "XLActionController", targets: ["XLActionController"]), 21 | .library(name: "XLActionControllerSkype", targets: ["XLActionController_Skype"]), 22 | .library(name: "XLActionControllerPeriscope", targets: ["XLActionController_Periscope"]), 23 | .library(name: "XLActionControllerSpotify", targets: ["XLActionController_Spotify"]), 24 | .library(name: "XLActionControllerTweetbot", targets: ["XLActionController_Tweetbot"]), 25 | .library(name: "XLActionControllerTwitter", targets: ["XLActionController_Twitter"]), 26 | .library(name: "XLActionControllerYoutube", targets: ["XLActionController_Youtube"]) 27 | ], 28 | targets: [ 29 | .target(name: "XLActionController", path: "Source", 30 | resources: [Resource.process("Resource/ActionCell.xib")]), 31 | getExampleTarget(name: "Periscope"), 32 | getExampleTarget(name: "Skype"), 33 | getExampleTarget(name: "Spotify"), 34 | getExampleTarget(name: "Tweetbot"), 35 | getExampleTarget(name: "Twitter"), 36 | getExampleTarget(name: "Youtube"), 37 | ] 38 | ) 39 | -------------------------------------------------------------------------------- /Resource/ActionCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 38 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /Source/Action.swift: -------------------------------------------------------------------------------- 1 | // Action.swift 2 | // XLActionController ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | public enum ActionStyle { 30 | case `default` 31 | case cancel 32 | case destructive 33 | } 34 | 35 | public struct Action { 36 | 37 | public var enabled: Bool 38 | public var executeImmediatelyOnTouch = false 39 | 40 | public fileprivate(set) var data: T? 41 | public fileprivate(set) var style = ActionStyle.default 42 | public fileprivate(set) var handler: ((Action) -> Void)? 43 | 44 | public init(_ data: T?, style: ActionStyle, executeImmediatelyOnTouch: Bool = false, handler: ((Action) -> Void)?) { 45 | enabled = true 46 | self.executeImmediatelyOnTouch = executeImmediatelyOnTouch 47 | self.data = data 48 | self.style = style 49 | self.handler = handler 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Source/ActionCell.swift: -------------------------------------------------------------------------------- 1 | // ActionCell.swift 2 | // XLActionController ( https://github.com/xmartlabs/ActionCell ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | 27 | public protocol SeparatorCellType: NSObjectProtocol { 28 | func showSeparator() 29 | func hideSeparator() 30 | } 31 | 32 | open class ActionCell: UICollectionViewCell, SeparatorCellType { 33 | 34 | @IBOutlet open weak var actionTitleLabel: UILabel? 35 | @IBOutlet open weak var actionImageView: UIImageView? 36 | @IBOutlet open weak var actionDetailLabel: UILabel? 37 | @IBOutlet open weak var separatorView: UIView? 38 | 39 | @IBOutlet open weak var imageViewWidthConstraint: NSLayoutConstraint? 40 | 41 | var imageWidth: CGFloat = 0 42 | 43 | open override func awakeFromNib() { 44 | super.awakeFromNib() 45 | 46 | imageWidth = imageViewWidthConstraint?.constant ?? 0 47 | } 48 | 49 | open func setup(_ title: String?, detail: String?, image: UIImage?) { 50 | actionTitleLabel?.text = title 51 | actionDetailLabel?.text = detail 52 | actionImageView?.image = image 53 | 54 | imageViewWidthConstraint?.constant = image == nil ? 0 : imageWidth 55 | 56 | setNeedsLayout() 57 | } 58 | 59 | open func showSeparator() { 60 | separatorView?.alpha = 1.0 61 | } 62 | 63 | open func hideSeparator() { 64 | separatorView?.alpha = 0.0 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Source/ActionControllerSettings.swift: -------------------------------------------------------------------------------- 1 | // ActionControllerSettings.swiftg 2 | // XLActionController ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | 27 | public struct ActionControllerSettings { 28 | 29 | /** Struct that contains properties to configure the actions controller's behavior */ 30 | public struct Behavior { 31 | /** 32 | * A Boolean value that determines whether the action controller must be dismissed when the user taps the 33 | * background view. Its default value is `true`. 34 | */ 35 | public var hideOnTap = true 36 | /** 37 | * A Boolean value that determines whether the action controller must be dismissed when the user scroll down 38 | * the collection view. Its default value is `true`. 39 | * 40 | * @discussion If `scrollEnabled` value is `false`, this property is discarded and the action controller won't 41 | * be dismissed if the user scrolls down the collection view. 42 | */ 43 | public var hideOnScrollDown = true 44 | /** 45 | * A Boolean value that determines whether the collectionView's scroll is enabled. Its default value is `false` 46 | */ 47 | public var scrollEnabled = false 48 | /** 49 | * A Boolean value that controls whether the collection view scroll bounces past the edge of content and back 50 | * again. Its default value is `false` 51 | */ 52 | public var bounces = false 53 | /** 54 | * A Boolean value that determines whether if the collection view layout will use UIDynamics to animate its 55 | * items. Its default value is `false` 56 | */ 57 | public var useDynamics = false 58 | /** 59 | * A Boolean value that determines whether the navigation bar will hide when action controller is being 60 | * presented. Its default value is `true` 61 | */ 62 | public var hideNavigationBarOnShow = true 63 | } 64 | 65 | /** Struct that contains properties to configure the cancel view */ 66 | public struct CancelViewStyle { 67 | /** 68 | * A Boolean value that determines whether cancel view is shown. Its default value is `false`. Its default 69 | * value is `false`. 70 | */ 71 | public var showCancel = false 72 | /** 73 | * The cancel view's title. Its default value is "Cancel". 74 | */ 75 | public var title: String? = "Cancel" 76 | /** 77 | * The cancel view's title Font. 78 | */ 79 | public var titleFont: String = UIFont.systemFont(ofSize: 14).fontName 80 | /** 81 | * The cancel view's title Font Size. 82 | */ 83 | public var titleSize: CGFloat = 14.0 84 | /** 85 | * The cancel view's height. Its default value is `60`. 86 | */ 87 | public var height = CGFloat(60.0) 88 | /** 89 | * The cancel view's background color. Its default value is `UIColor.blackColor().colorWithAlphaComponent(0.8)`. 90 | */ 91 | public var backgroundColor = UIColor.black.withAlphaComponent(0.8) 92 | /** 93 | * The cancel view's title color. Its default value is `UIColor.white`. 94 | */ 95 | public var titleColor = UIColor.white 96 | /** 97 | * A Boolean value that determines whether the collection view can be partially covered by the 98 | * cancel view when it is pulled down. Its default value is `false` 99 | */ 100 | public var hideCollectionViewBehindCancelView = false 101 | } 102 | 103 | /** Struct that contains properties to configure the collection view's style */ 104 | public struct CollectionViewStyle { 105 | /** 106 | * A float that determines the margins between the collection view and the container view's margins. 107 | * Its default value is `0` 108 | */ 109 | public var lateralMargin: CGFloat = 0 110 | /** 111 | * A float that determines the cells' height when using UIDynamics to animate items. Its default value is `50`. 112 | */ 113 | public var cellHeightWhenDynamicsIsUsed: CGFloat = 50 114 | } 115 | 116 | /** Struct that contains properties to configure the animation when presenting the action controller */ 117 | public struct PresentAnimationStyle { 118 | /** 119 | * A float value that is used as damping for the animation block. Its default value is `1.0`. 120 | * @see: animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion: 121 | */ 122 | public var damping = CGFloat(1.0) 123 | /** 124 | * A float value that is used as delay for the animation block. Its default value is `0.0`. 125 | * @see: animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion: 126 | */ 127 | public var delay = TimeInterval(0.0) 128 | /** 129 | * A float value that determines the animation duration. Its default value is `0.7`. 130 | * @see: animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion: 131 | */ 132 | public var duration = TimeInterval(0.7) 133 | /** 134 | * A float value that is used as `springVelocity` for the animation block. Its default value is `0.0`. 135 | * @see: animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion: 136 | */ 137 | public var springVelocity = CGFloat(0.0) 138 | /** 139 | * A mask of options indicating how you want to perform the animations. Its default value is `UIViewAnimationOptions.CurveEaseOut`. 140 | * @see: animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion: 141 | */ 142 | public var options = UIView.AnimationOptions.curveEaseOut 143 | } 144 | 145 | /** Struct that contains properties to configure the animation when dismissing the action controller */ 146 | public struct DismissAnimationStyle { 147 | /** 148 | * A float value that is used as damping for the animation block. Its default value is `1.0`. 149 | * @see: animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion: 150 | */ 151 | public var damping = CGFloat(1.0) 152 | /** 153 | * A float value that is used as delay for the animation block. Its default value is `0.0`. 154 | * @see: animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion: 155 | */ 156 | public var delay = TimeInterval(0.0) 157 | /** 158 | * A float value that determines the animation duration. Its default value is `0.7`. 159 | * @see: animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion: 160 | */ 161 | public var duration = TimeInterval(0.7) 162 | /** 163 | * A float value that is used as `springVelocity` for the animation block. Its default value is `0.0`. 164 | * @see: animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion: 165 | */ 166 | public var springVelocity = CGFloat(0.0) 167 | /** 168 | * A mask of options indicating how you want to perform the animations. Its default value is `UIViewAnimationOptions.CurveEaseIn`. 169 | * @see: animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion: 170 | */ 171 | public var options = UIView.AnimationOptions.curveEaseIn 172 | /** 173 | * A float value that makes the action controller's to be animated until the bottomof the screen plus this value. 174 | */ 175 | public var offset = CGFloat(0) 176 | } 177 | 178 | /** Struct that contains all properties related to presentation & dismissal animations */ 179 | public struct AnimationStyle { 180 | /** 181 | * A size value that is used to scale the presenting view controller when the action controller is being 182 | * presented. If `nil` is set, then the presenting view controller won't be scaled. Its default value is 183 | * `(0.9, 0.9)`. 184 | */ 185 | public var scale: CGSize? = CGSize(width: 0.9, height: 0.9) 186 | /** Stores presentation animation properties */ 187 | public var present = PresentAnimationStyle() 188 | /** Stores dismissal animation properties */ 189 | public var dismiss = DismissAnimationStyle() 190 | } 191 | 192 | /** Struct that contains properties related to the status bar's appearance */ 193 | public struct StatusBarStyle { 194 | /** 195 | * A Boolean value that determines whether the status bar should be visible or hidden when the action controller 196 | * is visible. Its default value is `true`. 197 | */ 198 | public var showStatusBar = true 199 | /** 200 | * A value that determines the style of the device’s status bar when the action controller is visible. Its 201 | * default value is `UIStatusBarStyle.LightContent`. 202 | */ 203 | public var style = UIStatusBarStyle.lightContent 204 | /** 205 | * A boolean value that determines whether the action controller takes over control of status bar appearance from the presenting 206 | * view controller. Its default value is `true`. 207 | * 208 | * For more information refer to `UIViewController.modalPresentationCapturesStatusBarAppearance`, 209 | * https://developer.apple.com/reference/uikit/uiviewcontroller/1621453-modalpresentationcapturesstatusb 210 | */ 211 | public var modalPresentationCapturesStatusBarAppearance = true 212 | } 213 | 214 | /** Stores the behavior's properties values */ 215 | public var behavior = Behavior() 216 | /** Stores the cancel view's properties values */ 217 | public var cancelView = CancelViewStyle() 218 | /** Stores the collection view's properties values */ 219 | public var collectionView = CollectionViewStyle() 220 | /** Stores the animations' properties values */ 221 | public var animation = AnimationStyle() 222 | /** Stores the status bar's properties values */ 223 | public var statusBar = StatusBarStyle() 224 | 225 | /** 226 | * Create the default settings 227 | * @return The default value for settings 228 | */ 229 | public static func defaultSettings() -> ActionControllerSettings { 230 | return ActionControllerSettings() 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /Source/ActionData.swift: -------------------------------------------------------------------------------- 1 | // ActionData.swift 2 | // ActionData ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | public struct ActionData { 29 | 30 | public fileprivate(set) var title: String? 31 | public fileprivate(set) var subtitle: String? 32 | public fileprivate(set) var image: UIImage? 33 | 34 | public init(title: String) { 35 | self.title = title 36 | } 37 | 38 | public init(title: String, subtitle: String) { 39 | self.init(title: title) 40 | self.subtitle = subtitle 41 | } 42 | 43 | public init(title: String, subtitle: String, image: UIImage) { 44 | self.init(title: title, subtitle: subtitle) 45 | self.image = image 46 | } 47 | 48 | public init(title: String, image: UIImage) { 49 | self.init(title: title) 50 | self.image = image 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Source/DynamicCollectionViewFlowLayout.swift: -------------------------------------------------------------------------------- 1 | // DynamicCollectionViewFlowLayout.swiftg 2 | // DynamicCollectionViewFlowLayout ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( whttp://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | 27 | open class DynamicCollectionViewFlowLayout: UICollectionViewFlowLayout { 28 | 29 | 30 | // MARK: - Properties definition 31 | 32 | open var dynamicAnimator: UIDynamicAnimator? 33 | open var itemsAligment = UIControl.ContentHorizontalAlignment.center 34 | 35 | open lazy var collisionBehavior: UICollisionBehavior? = { 36 | let collision = UICollisionBehavior(items: []) 37 | return collision 38 | }() 39 | 40 | open lazy var dynamicItemBehavior: UIDynamicItemBehavior? = { 41 | let dynamic = UIDynamicItemBehavior(items: []) 42 | dynamic.allowsRotation = false 43 | return dynamic 44 | }() 45 | 46 | open lazy var gravityBehavior: UIGravityBehavior? = { 47 | let gravity = UIGravityBehavior(items: []) 48 | gravity.gravityDirection = CGVector(dx: 0, dy: -1) 49 | gravity.magnitude = 4.0 50 | return gravity 51 | }() 52 | 53 | open var useDynamicAnimator = false { 54 | didSet(newValue) { 55 | guard useDynamicAnimator != newValue else { 56 | return 57 | } 58 | 59 | if useDynamicAnimator { 60 | dynamicAnimator = UIDynamicAnimator(collectionViewLayout: self) 61 | 62 | dynamicAnimator!.addBehavior(collisionBehavior!) 63 | dynamicAnimator!.addBehavior(dynamicItemBehavior!) 64 | dynamicAnimator!.addBehavior(gravityBehavior!) 65 | } 66 | } 67 | } 68 | 69 | // MARK: - Intialize 70 | 71 | override init() { 72 | super.init() 73 | initialize() 74 | } 75 | 76 | required public init?(coder aDecoder: NSCoder) { 77 | super.init(coder: aDecoder) 78 | initialize() 79 | } 80 | 81 | fileprivate func initialize() { 82 | minimumInteritemSpacing = 0 83 | minimumLineSpacing = 0 84 | } 85 | 86 | // MARK: - UICollectionViewFlowLayout overrides 87 | 88 | override open func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { 89 | guard let animator = dynamicAnimator else { 90 | return super.layoutAttributesForElements(in: rect) 91 | } 92 | 93 | let items = animator.items(in: rect) as NSArray 94 | return items.compactMap { $0 as? UICollectionViewLayoutAttributes } 95 | } 96 | 97 | override open func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { 98 | let indexPath = indexPath 99 | 100 | guard let animator = dynamicAnimator else { 101 | return super.layoutAttributesForItem(at: indexPath) 102 | } 103 | 104 | return animator.layoutAttributesForCell(at: indexPath) ?? setupAttributesForIndexPath(indexPath) 105 | } 106 | 107 | override open func prepare(forCollectionViewUpdates updateItems: [UICollectionViewUpdateItem]) { 108 | super.prepare(forCollectionViewUpdates: updateItems) 109 | 110 | updateItems.filter { $0.updateAction == .insert && layoutAttributesForItem(at: $0.indexPathAfterUpdate!) == nil } .forEach { 111 | setupAttributesForIndexPath($0.indexPathAfterUpdate) 112 | } 113 | } 114 | 115 | // MARK: - Helpers 116 | 117 | fileprivate func topForItemAt(indexPath: IndexPath) -> CGFloat { 118 | guard let unwrappedCollectionView = collectionView else { 119 | return CGFloat(0.0) 120 | } 121 | 122 | // Top within item's section 123 | var top = CGFloat((indexPath as NSIndexPath).item) * itemSize.height 124 | 125 | if (indexPath as NSIndexPath).section > 0 { 126 | let lastItemOfPrevSection = unwrappedCollectionView.numberOfItems(inSection: (indexPath as NSIndexPath).section - 1) 127 | // Add previous sections height recursively. We have to add the sectionInsets and the last section's item height 128 | let inset = (unwrappedCollectionView.delegate as? UICollectionViewDelegateFlowLayout)?.collectionView?(unwrappedCollectionView, layout: self, insetForSectionAt: (indexPath as NSIndexPath).section) ?? sectionInset 129 | top += topForItemAt(indexPath: IndexPath(item: lastItemOfPrevSection - 1, section: (indexPath as NSIndexPath).section - 1)) + inset.bottom + inset.top + itemSize.height 130 | } 131 | 132 | return top 133 | } 134 | 135 | private func isRTL(for view: UIView) -> Bool { 136 | return UIView.userInterfaceLayoutDirection(for: view.semanticContentAttribute) == .rightToLeft 137 | } 138 | 139 | @discardableResult 140 | func setupAttributesForIndexPath(_ indexPath: IndexPath?) -> UICollectionViewLayoutAttributes? { 141 | guard let indexPath = indexPath, let animator = dynamicAnimator, let collectionView = collectionView else { 142 | return nil 143 | } 144 | 145 | let delegate: UICollectionViewDelegateFlowLayout = collectionView.delegate as! UICollectionViewDelegateFlowLayout 146 | 147 | let collectionItemSize = delegate.collectionView!(collectionView, layout: self, sizeForItemAt: indexPath) 148 | 149 | // UIDynamic animator will animate this item from initialFrame to finalFrame. 150 | 151 | // Items will be animated from far bottom to its final position in the collection view layout 152 | let originY = collectionView.frame.size.height - collectionView.contentInset.top 153 | var frame = CGRect(x: 0, y: topForItemAt(indexPath: indexPath), width: collectionItemSize.width, height: collectionItemSize.height) 154 | var initialFrame = CGRect(x: 0, y: originY + frame.origin.y, width: collectionItemSize.width, height: collectionItemSize.height) 155 | 156 | // Calculate x position depending on alignment value 157 | 158 | let collectionViewContentWidth = collectionView.bounds.size.width - collectionView.contentInset.left - collectionView.contentInset.right 159 | let rightMargin = (collectionViewContentWidth - frame.size.width) 160 | let leftMargin = CGFloat(0.0) 161 | 162 | var translationX: CGFloat 163 | switch itemsAligment { 164 | case .center: 165 | translationX = (collectionViewContentWidth - frame.size.width) * 0.5 166 | case .fill, .left: 167 | translationX = leftMargin 168 | case .right: 169 | translationX = rightMargin 170 | case .leading: 171 | translationX = isRTL(for: collectionView) ? rightMargin : leftMargin 172 | case .trailing: 173 | translationX = isRTL(for: collectionView) ? leftMargin : rightMargin 174 | @unknown default: 175 | translationX = isRTL(for: collectionView) ? rightMargin : leftMargin 176 | } 177 | 178 | frame.origin.x = translationX 179 | initialFrame.origin.x = translationX 180 | 181 | let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath) 182 | attributes.frame = initialFrame 183 | 184 | let attachmentBehavior: UIAttachmentBehavior 185 | 186 | let collisionBehavior = UICollisionBehavior(items: [attributes]) 187 | 188 | let itemBehavior = UIDynamicItemBehavior(items: [attributes]) 189 | itemBehavior.allowsRotation = false 190 | 191 | if (indexPath as NSIndexPath).item == 0 { 192 | let mass = CGFloat(collectionView.numberOfItems(inSection: (indexPath as NSIndexPath).section)) 193 | 194 | itemBehavior.elasticity = (0.70 / mass) 195 | 196 | var topMargin = CGFloat(1.5) 197 | if (indexPath as NSIndexPath).section > 0 { 198 | topMargin -= sectionInset.top + sectionInset.bottom 199 | } 200 | let fromPoint = CGPoint(x: frame.minX, y: frame.minY + topMargin) 201 | let toPoint = CGPoint(x: frame.maxX, y: fromPoint.y) 202 | collisionBehavior.addBoundary(withIdentifier: "top" as NSCopying, from: fromPoint, to: toPoint) 203 | 204 | attachmentBehavior = UIAttachmentBehavior(item: attributes, attachedToAnchor:CGPoint(x: frame.midX, y: frame.midY)) 205 | attachmentBehavior.length = 1 206 | attachmentBehavior.damping = 0.30 * sqrt(mass) 207 | attachmentBehavior.frequency = 5.0 208 | 209 | } else { 210 | itemBehavior.elasticity = 0.0 211 | 212 | let fromPoint = CGPoint(x: frame.minX, y: frame.minY) 213 | let toPoint = CGPoint(x: frame.maxX, y: fromPoint.y) 214 | collisionBehavior.addBoundary(withIdentifier: "top" as NSCopying, from: fromPoint, to: toPoint) 215 | 216 | let prevPath = IndexPath(item: (indexPath as NSIndexPath).item - 1, section: (indexPath as NSIndexPath).section) 217 | let prevItemAttributes = layoutAttributesForItem(at: prevPath)! 218 | attachmentBehavior = UIAttachmentBehavior(item: attributes, attachedTo: prevItemAttributes) 219 | attachmentBehavior.length = itemSize.height 220 | attachmentBehavior.damping = 0.0 221 | attachmentBehavior.frequency = 0.0 222 | } 223 | 224 | animator.addBehavior(attachmentBehavior) 225 | animator.addBehavior(collisionBehavior) 226 | animator.addBehavior(itemBehavior) 227 | 228 | return attributes 229 | } 230 | 231 | open override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { 232 | guard let animator = dynamicAnimator else { 233 | return super.shouldInvalidateLayout(forBoundsChange: newBounds) 234 | } 235 | 236 | guard let unwrappedCollectionView = collectionView else { 237 | return super.shouldInvalidateLayout(forBoundsChange: newBounds) 238 | } 239 | 240 | animator.behaviors 241 | .filter { $0 is UIAttachmentBehavior || $0 is UICollisionBehavior || $0 is UIDynamicItemBehavior} 242 | .forEach { animator.removeBehavior($0) } 243 | 244 | for section in 0.. 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Source/XLActionController.h: -------------------------------------------------------------------------------- 1 | // XLActionController.swiftg 2 | // XLActionController ( https://github.com/xmartlabs/XLActionController ) 3 | // 4 | // Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | #import 26 | 27 | //! Project version number for XLActionController. 28 | FOUNDATION_EXPORT double XLActionControllerVersionNumber; 29 | 30 | //! Project version string for XLActionController. 31 | FOUNDATION_EXPORT const unsigned char XLActionControllerVersionString[]; 32 | 33 | // In this header, you should import all the public headers of your framework using statements like #import 34 | 35 | 36 | -------------------------------------------------------------------------------- /Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Tests/XLActionControllerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // XLActionControllerTests.swift 3 | // XLActionControllerTests 4 | // 5 | // Created by Martin Barreto on 11/16/15. 6 | // Copyright © 2015 Xmartlabs. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import XLActionController 11 | 12 | class XLActionControllerTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /XLActionController.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/XLActionController/c688f2606665cd1aa14a297ae3353f20b3a8ef86/XLActionController.png -------------------------------------------------------------------------------- /XLActionController.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | spec.name = 'XLActionController' 3 | spec.version = '5.1.0' 4 | spec.license = 'MIT' 5 | spec.summary = 'Fully customizable and extensible action sheet controller written in Swift' 6 | spec.homepage = 'https://github.com/xmartlabs/XLActionController' 7 | spec.social_media_url = 'https://twitter.com/xmartlabs' 8 | spec.authors = { 'Miguel Revetria' => 'miguel@xmartlabs.com', 'Martin Barreto' => 'martin@xmartlabs.com' } 9 | spec.source = { :git => 'https://github.com/xmartlabs/XLActionController.git', :tag => spec.version } 10 | spec.ios.deployment_target = '9.3' 11 | spec.ios.frameworks = 'UIKit', 'Foundation', 'CoreGraphics' 12 | spec.requires_arc = true 13 | spec.swift_version = '5.0' 14 | 15 | # Core subspec 16 | spec.subspec 'Core' do |core| 17 | core.source_files = ['Source/*.swift', 'Source/*.xib'] 18 | core.resources = 'Resource/*.xib' 19 | end 20 | 21 | # One subspec for each example provided by the library 22 | subspecs = [ 23 | 'Periscope', 24 | 'Skype', 25 | 'Spotify', 26 | 'Tweetbot', 27 | 'Twitter', 28 | 'Youtube' 29 | ] 30 | 31 | subspecs.each do |name| 32 | spec.subspec name do |subspec| 33 | subspec.dependency 'XLActionController/Core' 34 | subspec.source_files = ["Example/CustomActionControllers/#{name}/#{name}.swift", "Example/CustomActionControllers/#{name}/#{name}*.xib"] 35 | end 36 | end 37 | 38 | # By default install just the Core subspec code 39 | spec.default_subspec = 'Core' 40 | end 41 | -------------------------------------------------------------------------------- /XLActionController.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 28473B871C109E4900A8105F /* XLActionControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28473B851C109E3F00A8105F /* XLActionControllerTests.swift */; }; 11 | 28B3B8411BFA668F007337A2 /* ActionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B3B8361BFA668F007337A2 /* ActionCell.swift */; }; 12 | 28B3B8421BFA668F007337A2 /* ActionCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28B3B8371BFA668F007337A2 /* ActionCell.xib */; }; 13 | 28B3B8431BFA668F007337A2 /* ActionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B3B8381BFA668F007337A2 /* ActionController.swift */; }; 14 | 28B3B8441BFA668F007337A2 /* ActionControllerSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B3B8391BFA668F007337A2 /* ActionControllerSettings.swift */; }; 15 | 28B3B8451BFA668F007337A2 /* DynamicCollectionViewFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B3B83A1BFA668F007337A2 /* DynamicCollectionViewFlowLayout.swift */; }; 16 | 28B3B8471BFA668F007337A2 /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B3B83C1BFA668F007337A2 /* Action.swift */; }; 17 | 28B3B84C1BFA6E39007337A2 /* XLActionController.h in Headers */ = {isa = PBXBuildFile; fileRef = 28B3B84B1BFA6E39007337A2 /* XLActionController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 18 | 28E191721BFA618F00066B1C /* XLActionController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28E191671BFA618E00066B1C /* XLActionController.framework */; }; 19 | C74DEDA425D2C060009A9DFA /* ActionData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C74DEDA225D2C060009A9DFA /* ActionData.swift */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXContainerItemProxy section */ 23 | 28E191731BFA618F00066B1C /* PBXContainerItemProxy */ = { 24 | isa = PBXContainerItemProxy; 25 | containerPortal = 28E1915E1BFA618E00066B1C /* Project object */; 26 | proxyType = 1; 27 | remoteGlobalIDString = 28E191661BFA618E00066B1C; 28 | remoteInfo = XLActionController; 29 | }; 30 | /* End PBXContainerItemProxy section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 28473B851C109E3F00A8105F /* XLActionControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = XLActionControllerTests.swift; path = Tests/XLActionControllerTests.swift; sourceTree = SOURCE_ROOT; }; 34 | 28B3B8361BFA668F007337A2 /* ActionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ActionCell.swift; path = Source/ActionCell.swift; sourceTree = SOURCE_ROOT; }; 35 | 28B3B8371BFA668F007337A2 /* ActionCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ActionCell.xib; sourceTree = ""; }; 36 | 28B3B8381BFA668F007337A2 /* ActionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ActionController.swift; path = Source/ActionController.swift; sourceTree = SOURCE_ROOT; }; 37 | 28B3B8391BFA668F007337A2 /* ActionControllerSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ActionControllerSettings.swift; path = Source/ActionControllerSettings.swift; sourceTree = SOURCE_ROOT; }; 38 | 28B3B83A1BFA668F007337A2 /* DynamicCollectionViewFlowLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DynamicCollectionViewFlowLayout.swift; path = Source/DynamicCollectionViewFlowLayout.swift; sourceTree = SOURCE_ROOT; }; 39 | 28B3B83C1BFA668F007337A2 /* Action.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Action.swift; path = Source/Action.swift; sourceTree = SOURCE_ROOT; }; 40 | 28B3B84B1BFA6E39007337A2 /* XLActionController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XLActionController.h; path = Source/XLActionController.h; sourceTree = SOURCE_ROOT; }; 41 | 28E191671BFA618E00066B1C /* XLActionController.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = XLActionController.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | 28E1916C1BFA618F00066B1C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 43 | 28E191711BFA618F00066B1C /* XLActionControllerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = XLActionControllerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | 28E191781BFA618F00066B1C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | C74DED9925D2B82A009A9DFA /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 46 | C74DEDA225D2C060009A9DFA /* ActionData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionData.swift; sourceTree = ""; }; 47 | /* End PBXFileReference section */ 48 | 49 | /* Begin PBXFrameworksBuildPhase section */ 50 | 28E191631BFA618E00066B1C /* Frameworks */ = { 51 | isa = PBXFrameworksBuildPhase; 52 | buildActionMask = 2147483647; 53 | files = ( 54 | ); 55 | runOnlyForDeploymentPostprocessing = 0; 56 | }; 57 | 28E1916E1BFA618F00066B1C /* Frameworks */ = { 58 | isa = PBXFrameworksBuildPhase; 59 | buildActionMask = 2147483647; 60 | files = ( 61 | 28E191721BFA618F00066B1C /* XLActionController.framework in Frameworks */, 62 | ); 63 | runOnlyForDeploymentPostprocessing = 0; 64 | }; 65 | /* End PBXFrameworksBuildPhase section */ 66 | 67 | /* Begin PBXGroup section */ 68 | 28E1915D1BFA618E00066B1C = { 69 | isa = PBXGroup; 70 | children = ( 71 | EA2CFE281FBD2FBB00CAE00E /* Resource */, 72 | 28E191691BFA618E00066B1C /* Source */, 73 | 28E191751BFA618F00066B1C /* Tests */, 74 | C74DEDDE25D319F7009A9DFA /* Package */, 75 | 28E191681BFA618E00066B1C /* Products */, 76 | ); 77 | sourceTree = ""; 78 | }; 79 | 28E191681BFA618E00066B1C /* Products */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 28E191671BFA618E00066B1C /* XLActionController.framework */, 83 | 28E191711BFA618F00066B1C /* XLActionControllerTests.xctest */, 84 | ); 85 | name = Products; 86 | sourceTree = ""; 87 | }; 88 | 28E191691BFA618E00066B1C /* Source */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | C74DEDA225D2C060009A9DFA /* ActionData.swift */, 92 | 28B3B84B1BFA6E39007337A2 /* XLActionController.h */, 93 | 28B3B8361BFA668F007337A2 /* ActionCell.swift */, 94 | 28B3B8381BFA668F007337A2 /* ActionController.swift */, 95 | 28B3B8391BFA668F007337A2 /* ActionControllerSettings.swift */, 96 | 28B3B83A1BFA668F007337A2 /* DynamicCollectionViewFlowLayout.swift */, 97 | 28B3B83C1BFA668F007337A2 /* Action.swift */, 98 | 28E1916C1BFA618F00066B1C /* Info.plist */, 99 | ); 100 | path = Source; 101 | sourceTree = ""; 102 | }; 103 | 28E191751BFA618F00066B1C /* Tests */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 28473B851C109E3F00A8105F /* XLActionControllerTests.swift */, 107 | 28E191781BFA618F00066B1C /* Info.plist */, 108 | ); 109 | path = Tests; 110 | sourceTree = ""; 111 | }; 112 | C74DEDDE25D319F7009A9DFA /* Package */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | C74DED9925D2B82A009A9DFA /* Package.swift */, 116 | ); 117 | name = Package; 118 | sourceTree = ""; 119 | }; 120 | EA2CFE281FBD2FBB00CAE00E /* Resource */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | 28B3B8371BFA668F007337A2 /* ActionCell.xib */, 124 | ); 125 | path = Resource; 126 | sourceTree = ""; 127 | }; 128 | /* End PBXGroup section */ 129 | 130 | /* Begin PBXHeadersBuildPhase section */ 131 | 28E191641BFA618E00066B1C /* Headers */ = { 132 | isa = PBXHeadersBuildPhase; 133 | buildActionMask = 2147483647; 134 | files = ( 135 | 28B3B84C1BFA6E39007337A2 /* XLActionController.h in Headers */, 136 | ); 137 | runOnlyForDeploymentPostprocessing = 0; 138 | }; 139 | /* End PBXHeadersBuildPhase section */ 140 | 141 | /* Begin PBXNativeTarget section */ 142 | 28E191661BFA618E00066B1C /* XLActionController */ = { 143 | isa = PBXNativeTarget; 144 | buildConfigurationList = 28E1917B1BFA618F00066B1C /* Build configuration list for PBXNativeTarget "XLActionController" */; 145 | buildPhases = ( 146 | 28E191621BFA618E00066B1C /* Sources */, 147 | 28E191631BFA618E00066B1C /* Frameworks */, 148 | 28E191641BFA618E00066B1C /* Headers */, 149 | 28E191651BFA618E00066B1C /* Resources */, 150 | ); 151 | buildRules = ( 152 | ); 153 | dependencies = ( 154 | ); 155 | name = XLActionController; 156 | productName = XLActionController; 157 | productReference = 28E191671BFA618E00066B1C /* XLActionController.framework */; 158 | productType = "com.apple.product-type.framework"; 159 | }; 160 | 28E191701BFA618F00066B1C /* XLActionControllerTests */ = { 161 | isa = PBXNativeTarget; 162 | buildConfigurationList = 28E1917E1BFA618F00066B1C /* Build configuration list for PBXNativeTarget "XLActionControllerTests" */; 163 | buildPhases = ( 164 | 28E1916D1BFA618F00066B1C /* Sources */, 165 | 28E1916E1BFA618F00066B1C /* Frameworks */, 166 | 28E1916F1BFA618F00066B1C /* Resources */, 167 | ); 168 | buildRules = ( 169 | ); 170 | dependencies = ( 171 | 28E191741BFA618F00066B1C /* PBXTargetDependency */, 172 | ); 173 | name = XLActionControllerTests; 174 | productName = XLActionControllerTests; 175 | productReference = 28E191711BFA618F00066B1C /* XLActionControllerTests.xctest */; 176 | productType = "com.apple.product-type.bundle.unit-test"; 177 | }; 178 | /* End PBXNativeTarget section */ 179 | 180 | /* Begin PBXProject section */ 181 | 28E1915E1BFA618E00066B1C /* Project object */ = { 182 | isa = PBXProject; 183 | attributes = { 184 | LastSwiftUpdateCheck = 0710; 185 | LastUpgradeCheck = 1020; 186 | ORGANIZATIONNAME = Xmartlabs; 187 | TargetAttributes = { 188 | 28E191661BFA618E00066B1C = { 189 | CreatedOnToolsVersion = 7.1; 190 | LastSwiftMigration = 1020; 191 | }; 192 | 28E191701BFA618F00066B1C = { 193 | CreatedOnToolsVersion = 7.1; 194 | LastSwiftMigration = 1020; 195 | }; 196 | }; 197 | }; 198 | buildConfigurationList = 28E191611BFA618E00066B1C /* Build configuration list for PBXProject "XLActionController" */; 199 | compatibilityVersion = "Xcode 3.2"; 200 | developmentRegion = en; 201 | hasScannedForEncodings = 0; 202 | knownRegions = ( 203 | en, 204 | Base, 205 | ); 206 | mainGroup = 28E1915D1BFA618E00066B1C; 207 | productRefGroup = 28E191681BFA618E00066B1C /* Products */; 208 | projectDirPath = ""; 209 | projectRoot = ""; 210 | targets = ( 211 | 28E191661BFA618E00066B1C /* XLActionController */, 212 | 28E191701BFA618F00066B1C /* XLActionControllerTests */, 213 | ); 214 | }; 215 | /* End PBXProject section */ 216 | 217 | /* Begin PBXResourcesBuildPhase section */ 218 | 28E191651BFA618E00066B1C /* Resources */ = { 219 | isa = PBXResourcesBuildPhase; 220 | buildActionMask = 2147483647; 221 | files = ( 222 | 28B3B8421BFA668F007337A2 /* ActionCell.xib in Resources */, 223 | ); 224 | runOnlyForDeploymentPostprocessing = 0; 225 | }; 226 | 28E1916F1BFA618F00066B1C /* Resources */ = { 227 | isa = PBXResourcesBuildPhase; 228 | buildActionMask = 2147483647; 229 | files = ( 230 | ); 231 | runOnlyForDeploymentPostprocessing = 0; 232 | }; 233 | /* End PBXResourcesBuildPhase section */ 234 | 235 | /* Begin PBXSourcesBuildPhase section */ 236 | 28E191621BFA618E00066B1C /* Sources */ = { 237 | isa = PBXSourcesBuildPhase; 238 | buildActionMask = 2147483647; 239 | files = ( 240 | 28B3B8471BFA668F007337A2 /* Action.swift in Sources */, 241 | 28B3B8451BFA668F007337A2 /* DynamicCollectionViewFlowLayout.swift in Sources */, 242 | 28B3B8411BFA668F007337A2 /* ActionCell.swift in Sources */, 243 | C74DEDA425D2C060009A9DFA /* ActionData.swift in Sources */, 244 | 28B3B8441BFA668F007337A2 /* ActionControllerSettings.swift in Sources */, 245 | 28B3B8431BFA668F007337A2 /* ActionController.swift in Sources */, 246 | ); 247 | runOnlyForDeploymentPostprocessing = 0; 248 | }; 249 | 28E1916D1BFA618F00066B1C /* Sources */ = { 250 | isa = PBXSourcesBuildPhase; 251 | buildActionMask = 2147483647; 252 | files = ( 253 | 28473B871C109E4900A8105F /* XLActionControllerTests.swift in Sources */, 254 | ); 255 | runOnlyForDeploymentPostprocessing = 0; 256 | }; 257 | /* End PBXSourcesBuildPhase section */ 258 | 259 | /* Begin PBXTargetDependency section */ 260 | 28E191741BFA618F00066B1C /* PBXTargetDependency */ = { 261 | isa = PBXTargetDependency; 262 | target = 28E191661BFA618E00066B1C /* XLActionController */; 263 | targetProxy = 28E191731BFA618F00066B1C /* PBXContainerItemProxy */; 264 | }; 265 | /* End PBXTargetDependency section */ 266 | 267 | /* Begin XCBuildConfiguration section */ 268 | 28E191791BFA618F00066B1C /* Debug */ = { 269 | isa = XCBuildConfiguration; 270 | buildSettings = { 271 | ALWAYS_SEARCH_USER_PATHS = NO; 272 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 273 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 274 | CLANG_CXX_LIBRARY = "libc++"; 275 | CLANG_ENABLE_MODULES = YES; 276 | CLANG_ENABLE_OBJC_ARC = YES; 277 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 278 | CLANG_WARN_BOOL_CONVERSION = YES; 279 | CLANG_WARN_COMMA = YES; 280 | CLANG_WARN_CONSTANT_CONVERSION = YES; 281 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 282 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 283 | CLANG_WARN_EMPTY_BODY = YES; 284 | CLANG_WARN_ENUM_CONVERSION = YES; 285 | CLANG_WARN_INFINITE_RECURSION = YES; 286 | CLANG_WARN_INT_CONVERSION = YES; 287 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 288 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 289 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 290 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 291 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 292 | CLANG_WARN_STRICT_PROTOTYPES = YES; 293 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 294 | CLANG_WARN_UNREACHABLE_CODE = YES; 295 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 296 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 297 | COPY_PHASE_STRIP = NO; 298 | CURRENT_PROJECT_VERSION = 1; 299 | DEBUG_INFORMATION_FORMAT = dwarf; 300 | ENABLE_STRICT_OBJC_MSGSEND = YES; 301 | ENABLE_TESTABILITY = YES; 302 | GCC_C_LANGUAGE_STANDARD = gnu99; 303 | GCC_DYNAMIC_NO_PIC = NO; 304 | GCC_NO_COMMON_BLOCKS = YES; 305 | GCC_OPTIMIZATION_LEVEL = 0; 306 | GCC_PREPROCESSOR_DEFINITIONS = ( 307 | "DEBUG=1", 308 | "$(inherited)", 309 | ); 310 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 311 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 312 | GCC_WARN_UNDECLARED_SELECTOR = YES; 313 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 314 | GCC_WARN_UNUSED_FUNCTION = YES; 315 | GCC_WARN_UNUSED_VARIABLE = YES; 316 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 317 | MTL_ENABLE_DEBUG_INFO = YES; 318 | ONLY_ACTIVE_ARCH = YES; 319 | SDKROOT = iphoneos; 320 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 321 | SWIFT_VERSION = 4.0; 322 | TARGETED_DEVICE_FAMILY = "1,2"; 323 | VERSIONING_SYSTEM = "apple-generic"; 324 | VERSION_INFO_PREFIX = ""; 325 | }; 326 | name = Debug; 327 | }; 328 | 28E1917A1BFA618F00066B1C /* Release */ = { 329 | isa = XCBuildConfiguration; 330 | buildSettings = { 331 | ALWAYS_SEARCH_USER_PATHS = NO; 332 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 333 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 334 | CLANG_CXX_LIBRARY = "libc++"; 335 | CLANG_ENABLE_MODULES = YES; 336 | CLANG_ENABLE_OBJC_ARC = YES; 337 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 338 | CLANG_WARN_BOOL_CONVERSION = YES; 339 | CLANG_WARN_COMMA = YES; 340 | CLANG_WARN_CONSTANT_CONVERSION = YES; 341 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 342 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 343 | CLANG_WARN_EMPTY_BODY = YES; 344 | CLANG_WARN_ENUM_CONVERSION = YES; 345 | CLANG_WARN_INFINITE_RECURSION = YES; 346 | CLANG_WARN_INT_CONVERSION = YES; 347 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 348 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 349 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 350 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 351 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 352 | CLANG_WARN_STRICT_PROTOTYPES = YES; 353 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 354 | CLANG_WARN_UNREACHABLE_CODE = YES; 355 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 356 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 357 | COPY_PHASE_STRIP = NO; 358 | CURRENT_PROJECT_VERSION = 1; 359 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 360 | ENABLE_NS_ASSERTIONS = NO; 361 | ENABLE_STRICT_OBJC_MSGSEND = YES; 362 | GCC_C_LANGUAGE_STANDARD = gnu99; 363 | GCC_NO_COMMON_BLOCKS = YES; 364 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 365 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 366 | GCC_WARN_UNDECLARED_SELECTOR = YES; 367 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 368 | GCC_WARN_UNUSED_FUNCTION = YES; 369 | GCC_WARN_UNUSED_VARIABLE = YES; 370 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 371 | MTL_ENABLE_DEBUG_INFO = NO; 372 | SDKROOT = iphoneos; 373 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 374 | SWIFT_VERSION = 4.0; 375 | TARGETED_DEVICE_FAMILY = "1,2"; 376 | VALIDATE_PRODUCT = YES; 377 | VERSIONING_SYSTEM = "apple-generic"; 378 | VERSION_INFO_PREFIX = ""; 379 | }; 380 | name = Release; 381 | }; 382 | 28E1917C1BFA618F00066B1C /* Debug */ = { 383 | isa = XCBuildConfiguration; 384 | buildSettings = { 385 | CLANG_ENABLE_MODULES = YES; 386 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 387 | DEFINES_MODULE = YES; 388 | DEVELOPMENT_TEAM = ""; 389 | DYLIB_COMPATIBILITY_VERSION = 1; 390 | DYLIB_CURRENT_VERSION = 1; 391 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 392 | INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist"; 393 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 394 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 395 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 396 | MARKETING_VERSION = 5.1.0; 397 | PRODUCT_BUNDLE_IDENTIFIER = com.xmartlabs.XLActionController; 398 | PRODUCT_NAME = "$(TARGET_NAME)"; 399 | SKIP_INSTALL = YES; 400 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 401 | SWIFT_VERSION = 5.0; 402 | }; 403 | name = Debug; 404 | }; 405 | 28E1917D1BFA618F00066B1C /* Release */ = { 406 | isa = XCBuildConfiguration; 407 | buildSettings = { 408 | CLANG_ENABLE_MODULES = YES; 409 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 410 | DEFINES_MODULE = YES; 411 | DEVELOPMENT_TEAM = ""; 412 | DYLIB_COMPATIBILITY_VERSION = 1; 413 | DYLIB_CURRENT_VERSION = 1; 414 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 415 | INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist"; 416 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 417 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 418 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 419 | MARKETING_VERSION = 5.1.0; 420 | PRODUCT_BUNDLE_IDENTIFIER = com.xmartlabs.XLActionController; 421 | PRODUCT_NAME = "$(TARGET_NAME)"; 422 | SKIP_INSTALL = YES; 423 | SWIFT_VERSION = 5.0; 424 | }; 425 | name = Release; 426 | }; 427 | 28E1917F1BFA618F00066B1C /* Debug */ = { 428 | isa = XCBuildConfiguration; 429 | buildSettings = { 430 | DEVELOPMENT_TEAM = ""; 431 | INFOPLIST_FILE = Tests/Info.plist; 432 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 433 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 434 | PRODUCT_BUNDLE_IDENTIFIER = com.xmartlabs.XLActionControllerTests; 435 | PRODUCT_NAME = "$(TARGET_NAME)"; 436 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 437 | SWIFT_VERSION = 5.0; 438 | }; 439 | name = Debug; 440 | }; 441 | 28E191801BFA618F00066B1C /* Release */ = { 442 | isa = XCBuildConfiguration; 443 | buildSettings = { 444 | DEVELOPMENT_TEAM = ""; 445 | INFOPLIST_FILE = Tests/Info.plist; 446 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 447 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 448 | PRODUCT_BUNDLE_IDENTIFIER = com.xmartlabs.XLActionControllerTests; 449 | PRODUCT_NAME = "$(TARGET_NAME)"; 450 | SWIFT_VERSION = 5.0; 451 | }; 452 | name = Release; 453 | }; 454 | /* End XCBuildConfiguration section */ 455 | 456 | /* Begin XCConfigurationList section */ 457 | 28E191611BFA618E00066B1C /* Build configuration list for PBXProject "XLActionController" */ = { 458 | isa = XCConfigurationList; 459 | buildConfigurations = ( 460 | 28E191791BFA618F00066B1C /* Debug */, 461 | 28E1917A1BFA618F00066B1C /* Release */, 462 | ); 463 | defaultConfigurationIsVisible = 0; 464 | defaultConfigurationName = Release; 465 | }; 466 | 28E1917B1BFA618F00066B1C /* Build configuration list for PBXNativeTarget "XLActionController" */ = { 467 | isa = XCConfigurationList; 468 | buildConfigurations = ( 469 | 28E1917C1BFA618F00066B1C /* Debug */, 470 | 28E1917D1BFA618F00066B1C /* Release */, 471 | ); 472 | defaultConfigurationIsVisible = 0; 473 | defaultConfigurationName = Release; 474 | }; 475 | 28E1917E1BFA618F00066B1C /* Build configuration list for PBXNativeTarget "XLActionControllerTests" */ = { 476 | isa = XCConfigurationList; 477 | buildConfigurations = ( 478 | 28E1917F1BFA618F00066B1C /* Debug */, 479 | 28E191801BFA618F00066B1C /* Release */, 480 | ); 481 | defaultConfigurationIsVisible = 0; 482 | defaultConfigurationName = Release; 483 | }; 484 | /* End XCConfigurationList section */ 485 | }; 486 | rootObject = 28E1915E1BFA618E00066B1C /* Project object */; 487 | } 488 | -------------------------------------------------------------------------------- /XLActionController.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /XLActionController.xcodeproj/xcshareddata/xcschemes/XLActionController.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 | -------------------------------------------------------------------------------- /XLActionController.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /XLActionController.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | --------------------------------------------------------------------------------