├── .github └── workflows │ └── pulls.yml ├── .gitignore ├── .hound.yml ├── .rubocop.yml ├── .ruby-version ├── .swiftlint.yml ├── .xcode-version ├── Artwork └── example.png ├── CHANGELOG.md ├── Example ├── .swiftlint.yml ├── Example.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Example.xcscheme ├── Example.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Example │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── App Icon & Top Shelf Image.brandassets │ │ │ ├── App Icon - Large.imagestack │ │ │ │ ├── Back.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ ├── Front.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ └── Middle.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ ├── App Icon - Small.imagestack │ │ │ │ ├── Back.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ ├── Front.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ └── Middle.imagestacklayer │ │ │ │ │ ├── Content.imageset │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ ├── Top Shelf Image Wide.imageset │ │ │ │ └── Contents.json │ │ │ └── Top Shelf Image.imageset │ │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── Example │ │ │ ├── Contents.json │ │ │ └── background.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── background.png │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ ├── Base.lproj │ │ └── Main.storyboard │ ├── Info.plist │ └── ViewController.swift ├── Podfile └── Podfile.lock ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── Package.resolved ├── Package.swift ├── Podfile ├── Podfile.lock ├── README.md ├── Resources ├── de.lproj │ └── Localizable.strings ├── en.lproj │ └── Localizable.strings ├── es-MX.lproj │ └── Localizable.strings ├── es.lproj │ └── Localizable.strings ├── fr.lproj │ └── Localizable.strings ├── it.lproj │ └── Localizable.strings ├── ja.lproj │ └── Localizable.strings ├── nb.lproj │ └── Localizable.strings ├── nl.lproj │ └── Localizable.strings └── ru.lproj │ └── Localizable.strings ├── Source ├── Info.plist ├── Private │ └── Helpers │ │ ├── BundleLoader.swift │ │ ├── LocalizedStrings.swift │ │ ├── String+Truncation.swift │ │ └── UIView+Autolayout.swift ├── Public │ └── Views │ │ └── TvOSMoreButton.swift └── TvOSMoreButton.h ├── Tests ├── Info.plist ├── Public │ └── Views │ │ ├── Tests_TvOSMoreButton.swift │ │ └── __Snapshots__ │ │ └── Tests_TvOSMoreButton │ │ ├── test_that_button_with_truncated_text_has_unfocused_appearance_after_being_focused.1.png │ │ ├── test_that_focused_button_with_truncated_text_renders_correctly.1.png │ │ ├── test_that_unfocused_button_with_text_that_fits_and_custom_content_inset_renders_correctly.1.png │ │ ├── test_that_unfocused_button_with_text_that_fits_and_custom_font_renders_correctly.1.png │ │ ├── test_that_unfocused_button_with_text_that_fits_and_custom_text_alignment_renders_correctly.1.png │ │ ├── test_that_unfocused_button_with_text_that_fits_and_custom_text_color_renders_correctly.1.png │ │ ├── test_that_unfocused_button_with_text_that_fits_renders_correctly.1.png │ │ ├── test_that_unfocused_button_with_truncated_text_and_and_custom_text_color_renders_correctly.1.png │ │ ├── test_that_unfocused_button_with_truncated_text_and_custom_content_inset_renders_correctly.1.png │ │ ├── test_that_unfocused_button_with_truncated_text_and_custom_ellipses_string_renders_correctly.1.png │ │ ├── test_that_unfocused_button_with_truncated_text_and_custom_font_renders_correctly.1.png │ │ ├── test_that_unfocused_button_with_truncated_text_and_custom_text_alignment_renders_correctly.1.png │ │ ├── test_that_unfocused_button_with_truncated_text_and_custom_trailing_text_color_renders_correctly.1.png │ │ ├── test_that_unfocused_button_with_truncated_text_and_custom_trailing_text_font_renders_correctly.1.png │ │ ├── test_that_unfocused_button_with_truncated_text_and_custom_trailing_text_renders_correctly.1.png │ │ └── test_that_unfocused_button_with_truncated_text_renders_correctly.1.png └── Resources │ └── Localizable.strings ├── TvOSMoreButton.podspec ├── TvOSMoreButton.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── TvOSMoreButton.xcscheme └── TvOSMoreButton.xcworkspace ├── contents.xcworkspacedata └── xcshareddata ├── IDEWorkspaceChecks.plist └── WorkspaceSettings.xcsettings /.github/workflows/pulls.yml: -------------------------------------------------------------------------------- 1 | name: Pulls 2 | 3 | on: 4 | pull_request: 5 | workflow_dispatch: 6 | 7 | concurrency: 8 | group: tests-${{ github.head_ref }} 9 | cancel-in-progress: true 10 | 11 | env: 12 | DEVELOPER_DIR: /Applications/Xcode_13.0.app 13 | 14 | jobs: 15 | linter: 16 | name: Linters 17 | runs-on: macos-11 18 | 19 | steps: 20 | - uses: actions/checkout@v2 21 | - uses: ruby/setup-ruby@v1 22 | with: 23 | bundler-cache: true 24 | - uses: actions/cache@v2 25 | with: 26 | path: | 27 | ~/Library/Caches/CocoaPods 28 | ~/.cocoapods 29 | Pods 30 | key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }} 31 | restore-keys: ${{ runner.os }}-pods- 32 | - run: bundle exec pod repo update 33 | - run: bundle exec pod install 34 | - run: bundle exec swiftlint 35 | 36 | tests-unit: 37 | name: Unit tests 38 | runs-on: macos-11 39 | 40 | steps: 41 | - uses: actions/checkout@v2 42 | - uses: ruby/setup-ruby@v1 43 | with: 44 | bundler-cache: true 45 | - uses: actions/cache@v2 46 | with: 47 | path: | 48 | ~/Library/Caches/CocoaPods 49 | ~/.cocoapods 50 | Pods 51 | key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }} 52 | restore-keys: ${{ runner.os }}-pods- 53 | - run: bundle exec pod repo update 54 | - run: bundle exec pod install 55 | - name: Select Xcode 56 | run: sudo xcode-select -switch /Applications/Xcode_13.0.app && /usr/bin/xcodebuild -version 57 | - name: Run tests 58 | run: xcodebuild test -scheme TvOSMoreButton -workspace TvOSMoreButton.xcworkspace -destination 'platform=tvOS Simulator,OS=15.0,name=Apple TV' 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | xcuserdata/ 3 | Pods 4 | /.swiftpm 5 | -------------------------------------------------------------------------------- /.hound.yml: -------------------------------------------------------------------------------- 1 | swift: 2 | config_file: .swiftlint.yml 3 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | Naming/FileName: 2 | Exclude: 3 | - '*.podspec' 4 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.7.3 2 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - function_parameter_count 3 | - identifier_name 4 | - line_length 5 | - statement_position 6 | - trailing_whitespace 7 | 8 | excluded: 9 | - Carthage 10 | - Pods 11 | - Example/Pods 12 | - Tests 13 | -------------------------------------------------------------------------------- /.xcode-version: -------------------------------------------------------------------------------- 1 | 13.2.1 2 | -------------------------------------------------------------------------------- /Artwork/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Artwork/example.png -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | `TvOSMoreButton` adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | #### 1.x Releases 6 | - `1.4.x` Releases - [1.4.0](#140) | [1.4.1](#141) 7 | - `1.3.x` Releases - [1.3.0](#130) 8 | - `1.2.x` Releases - [1.2.0](#120) | [1.2.1](#121) | [1.2.2](#122) | [1.2.3](#123) 9 | - `1.1.x` Releases - [1.1.0](#110) | [1.1.1](#111) | [1.1.2](#112) | [1.1.3](#113)| [1.1.4](#114) 10 | - `1.0.x` Releases - [1.0.0](#100) | [1.0.1](#101) | [1.0.2](#102) 11 | 12 | ## [1.4.1](https://github.com/cgoldsby/TvOSMoreButton/releases/tag/1.4.1) 13 | Released on 2022-04-18. 14 | ### Fix warning when using Xcode 13.2.1 🛠 15 | Fix Xcode warnings when using Xcode 13.2.1 (13C100) (#38) via Chris Goldsby. 16 | 17 | Have a happy spring everyone! 🌸 18 | 19 | ## [1.4.0](https://github.com/cgoldsby/TvOSMoreButton/releases/tag/1.4.0) 20 | Released on 2020-10-22. 21 | ### Support Swift Package Manager (SPM) 📦 22 | Support for Swift Package Manager (#35) via Markus Mueller. 23 | 24 | Personal thanks to everyone who contributed! 🙇 25 | 26 | ## [1.3.0](https://github.com/cgoldsby/TvOSMoreButton/releases/tag/1.3.0) 27 | Released on 2020-02-18. 28 | ### Update to Swift 5 🦉 29 | Support for building with Xcode 11 and Swift 5.0. This version requires Xcode 11 or later with Swift 5.0 compiler (#33) via David Cordero. 30 | 31 | Personal thanks to everyone who contributed! 🙇 32 | 33 | ## [1.2.3](https://github.com/cgoldsby/TvOSMoreButton/releases/tag/1.2.3) 34 | Released on 2019-01-16. 35 | ### More control over when button is focused 🔢 36 | This release adds new functionality, `focusableMode` to define when the button should be focus (#29). 37 | 38 | By default the focusable mode is set to `auto`. When the text is too long the button will be focusable, else it will not be focusable. This is the current behavior. 39 | 40 | In addition, you can set the focusable mode to `manual(_ isFocusable: Bool)`. This mode will force the button to be always be focused or never be focused. 41 | 42 | * Added `focusableMode` property (#29) via Roman Gritsuk 43 | 44 | Personal thanks to everyone who contributed! 🙇 45 | 46 | Let make 2019 a great year together! 👩‍💻👨‍💻 47 | 48 | ## [1.2.2](https://github.com/cgoldsby/TvOSMoreButton/releases/tag/1.2.2) 49 | Released on 2018-12-18. 50 | ### Incorrect Trailing Text Bug Fix 🐞 51 | This release fixes a bug (#26) where the trailing text was being truncated. 52 | 53 | * Fixes a bug where the trailing text is being truncated (#28) via Roman Gritsuk 54 | 55 | Personal thanks to everyone who contributed! 🙇 56 | 57 | 2019 is right around the corner! 😉 🎆 58 | 59 | ## [1.2.1](https://github.com/cgoldsby/TvOSMoreButton/releases/tag/1.2.1) 60 | Released on 2018-12-06. 61 | ### Incorrect Focus Style Bug Fix 🐛 62 | This release fixes a bug (#24) where the button (un)focused style is not correct. 63 | 64 | * Fixes a bug where the button (un)focused style is not correct (#25) via Chris Goldsby 65 | 66 | No API changes. 67 | 68 | Have a great winter everyone! Stay warm! And, if I don't see you, "Have a great New Year!" ⛄️ 69 | 70 | ## [1.2.0](https://github.com/cgoldsby/TvOSMoreButton/releases/tag/1.2.0) 71 | Released on 2018-10-15. 72 | ### Swift 4.2 🦉 73 | Support for building with Xcode 10 and Swift 4.2. This version requires Xcode 10 or later with Swift 4.2 compiler. 74 | 75 | No API changes. 76 | 77 | Have a great week everybody! 🎸 78 | 79 | ## [1.1.4](https://github.com/cgoldsby/TvOSMoreButton/releases/tag/1.1.4) 80 | Released on 2018-09-26. 81 | Added `textAlignment` property to improve right to left text support, e.g. Arabic language. 82 | 83 | * Added `textAlignment` (#18) via Furkan Hatipoglu 84 | 85 | Personal thanks to everyone who contributed! 🙇 86 | 87 | Almost October; may your Halloween be spooky! 🎃 88 | 89 | ## [1.1.3](https://github.com/cgoldsby/TvOSMoreButton/releases/tag/1.1.3) 90 | Released on 2018-09-01. 91 | ### Bug Fixes 🐛 92 | 93 | No API changes. 94 | 95 | * Update UI whenever `trailingText` & `ellipsesString` changes via Chris Goldsby 96 | 97 | Have a Happy Fall everyone! 🍂 98 | 99 | ## [1.1.2](https://github.com/cgoldsby/TvOSMoreButton/releases/tag/1.1.2) 100 | Released on 2018-05-26. 101 | ### Accessibility Updates ♿️ 102 | 103 | No API changes. 104 | 105 | * Add UIAccessibility (#14) via Chris Goldsby 106 | * Code style updates (#13) via Chris Goldsby 107 | 108 | Have a Happy Spring everyone! 🌻 109 | 110 | ## [1.1.1](https://github.com/cgoldsby/TvOSMoreButton/releases/tag/1.1.1) 111 | Released on 2017-10-26. 112 | ### Improved Carthage Documentation, Objective-C Support, & Deprecated Warning Fixes 113 | 114 | No API changes. 115 | 116 | * Document installation via Carthage (#8) via David Cordero 117 | * Objective-C Support (#9) via André Silva 118 | * Fix "characters was deprecated" warning (#10) via David Cordero 119 | 120 | What a great release! Personal thanks to everyone who contributed! 🙇 121 | 122 | Have a Happy Fall everyone! 🍂 123 | 124 | ## [1.1.0](https://github.com/cgoldsby/TvOSMoreButton/releases/tag/1.1.0) 125 | Released on 2017-09-16. 126 | ### Swift 4 and Xcode 9 127 | 128 | **Xcode 9 and 3.2+ is now required.** 129 | 130 | **Changes** 131 | 132 | This library has been migrated to Swift 4. 133 | 134 | No API changes. 135 | 136 | **Swift 3.2 Support** 137 | 138 | If your project is using Swift 3.2, you can still use this release by overriding the `SWIFT_VERSION` to be 4.0 in your Podfile. 139 | 140 | ```ruby 141 | post_install do |installer| 142 | installer.pods_project.targets.each do |target| 143 | if target.name == 'TvOSMoreButton' 144 | target.build_configurations.each do |config| 145 | config.build_settings['SWIFT_VERSION'] = '4.0' 146 | end 147 | end 148 | end 149 | end 150 | ``` 151 | 152 | Or, you can use the previous release, [1.0.2](https://github.com/cgoldsby/TvOSMoreButton/releases/tag/1.0.2), which does not require the `post_install` hook and will compile just fine with Xcode 9 and Swift 3.2. 153 | 154 | 🎉 155 | 156 | ## [1.0.2](https://github.com/cgoldsby/TvOSMoreButton/releases/tag/1.0.2) 157 | Released on 2017-04-23. 158 | ### Support More Localizations: 🇲🇽, 🇯🇵, 🇳🇱, 🇳🇴, 🇷🇺 159 | 160 | No API changes. 161 | 162 | #### Added 163 | 164 | The `TvOSMoreButton` is now localized in: 165 | 166 | Español Mexicano 🇲🇽 167 | Japanese 🇯🇵 168 | Dutch 🇳🇱 169 | Norwegian 🇳🇴 170 | Russian 🇷🇺 171 | 172 | ## [1.0.1](https://github.com/cgoldsby/TvOSMoreButton/releases/tag/1.0.1) 173 | Released on 2017-03-25. 174 | ### Support More Localizations: 🇩🇪, 🇫🇷, 🇪🇸, 🇮🇹 175 | 176 | No API changes. 177 | 178 | #### Added 179 | 180 | The `TvOSMoreButton` is now localized in: 181 | 182 | Español 🇩🇪 183 | French 🇫🇷 184 | Deutsch 🇪🇸 185 | Italian 🇮🇹 186 | 187 | ## [1.0.0](https://github.com/cgoldsby/TvOSMoreButton/releases/tag/1.0.0) 188 | Released on 2017-03-09. 189 | ### Initial Release 🎉 190 | -------------------------------------------------------------------------------- /Example/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | ../.swiftlint.yml -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D7FA19E00C3E16D7FEA0B610 /* Pods_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8952D64DAEE8BE54AA2B7DAC /* Pods_Example.framework */; }; 11 | EB7D94A31DBD0CE5006C67A5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7D94A21DBD0CE5006C67A5 /* AppDelegate.swift */; }; 12 | EB7D94A51DBD0CE5006C67A5 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB7D94A41DBD0CE5006C67A5 /* ViewController.swift */; }; 13 | EB7D94A81DBD0CE5006C67A5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EB7D94A61DBD0CE5006C67A5 /* Main.storyboard */; }; 14 | EB7D94AA1DBD0CE5006C67A5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EB7D94A91DBD0CE5006C67A5 /* Assets.xcassets */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | 41A4C3646154EDDFA23FB6A3 /* Pods-Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig"; sourceTree = ""; }; 19 | 8952D64DAEE8BE54AA2B7DAC /* Pods_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 20 | B920AB125D1C037B3325EE4E /* Pods-Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig"; sourceTree = ""; }; 21 | EB7D949F1DBD0CE5006C67A5 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 22 | EB7D94A21DBD0CE5006C67A5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 23 | EB7D94A41DBD0CE5006C67A5 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 24 | EB7D94A71DBD0CE5006C67A5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 25 | EB7D94A91DBD0CE5006C67A5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 26 | EB7D94AB1DBD0CE5006C67A5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 27 | /* End PBXFileReference section */ 28 | 29 | /* Begin PBXFrameworksBuildPhase section */ 30 | EB7D949C1DBD0CE5006C67A5 /* Frameworks */ = { 31 | isa = PBXFrameworksBuildPhase; 32 | buildActionMask = 2147483647; 33 | files = ( 34 | D7FA19E00C3E16D7FEA0B610 /* Pods_Example.framework in Frameworks */, 35 | ); 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXFrameworksBuildPhase section */ 39 | 40 | /* Begin PBXGroup section */ 41 | 1209332DFCB313A36EE2F6CF /* Frameworks */ = { 42 | isa = PBXGroup; 43 | children = ( 44 | 8952D64DAEE8BE54AA2B7DAC /* Pods_Example.framework */, 45 | ); 46 | name = Frameworks; 47 | sourceTree = ""; 48 | }; 49 | 7A814593DD2E9A20817F9FAD /* Pods */ = { 50 | isa = PBXGroup; 51 | children = ( 52 | B920AB125D1C037B3325EE4E /* Pods-Example.debug.xcconfig */, 53 | 41A4C3646154EDDFA23FB6A3 /* Pods-Example.release.xcconfig */, 54 | ); 55 | name = Pods; 56 | sourceTree = ""; 57 | }; 58 | EB7D94961DBD0CE5006C67A5 = { 59 | isa = PBXGroup; 60 | children = ( 61 | EB7D94A11DBD0CE5006C67A5 /* Example */, 62 | EB7D94A01DBD0CE5006C67A5 /* Products */, 63 | 7A814593DD2E9A20817F9FAD /* Pods */, 64 | 1209332DFCB313A36EE2F6CF /* Frameworks */, 65 | ); 66 | sourceTree = ""; 67 | }; 68 | EB7D94A01DBD0CE5006C67A5 /* Products */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | EB7D949F1DBD0CE5006C67A5 /* Example.app */, 72 | ); 73 | name = Products; 74 | sourceTree = ""; 75 | }; 76 | EB7D94A11DBD0CE5006C67A5 /* Example */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | EB7D94A21DBD0CE5006C67A5 /* AppDelegate.swift */, 80 | EB7D94A41DBD0CE5006C67A5 /* ViewController.swift */, 81 | EB7D94A61DBD0CE5006C67A5 /* Main.storyboard */, 82 | EB7D94A91DBD0CE5006C67A5 /* Assets.xcassets */, 83 | EB7D94AB1DBD0CE5006C67A5 /* Info.plist */, 84 | ); 85 | path = Example; 86 | sourceTree = ""; 87 | }; 88 | /* End PBXGroup section */ 89 | 90 | /* Begin PBXNativeTarget section */ 91 | EB7D949E1DBD0CE5006C67A5 /* Example */ = { 92 | isa = PBXNativeTarget; 93 | buildConfigurationList = EB7D94AE1DBD0CE5006C67A5 /* Build configuration list for PBXNativeTarget "Example" */; 94 | buildPhases = ( 95 | ADF842CC42160071963C8C6D /* [CP] Check Pods Manifest.lock */, 96 | EBEACC9E1E7159E60075CBD3 /* [Example] Linter */, 97 | EB7D949B1DBD0CE5006C67A5 /* Sources */, 98 | EB7D949C1DBD0CE5006C67A5 /* Frameworks */, 99 | EB7D949D1DBD0CE5006C67A5 /* Resources */, 100 | 12D698F5CA00610B397B218C /* [CP] Embed Pods Frameworks */, 101 | ); 102 | buildRules = ( 103 | ); 104 | dependencies = ( 105 | ); 106 | name = Example; 107 | productName = Example; 108 | productReference = EB7D949F1DBD0CE5006C67A5 /* Example.app */; 109 | productType = "com.apple.product-type.application"; 110 | }; 111 | /* End PBXNativeTarget section */ 112 | 113 | /* Begin PBXProject section */ 114 | EB7D94971DBD0CE5006C67A5 /* Project object */ = { 115 | isa = PBXProject; 116 | attributes = { 117 | LastSwiftUpdateCheck = 0800; 118 | LastUpgradeCheck = 1320; 119 | ORGANIZATIONNAME = "Christopher Goldsby"; 120 | TargetAttributes = { 121 | EB7D949E1DBD0CE5006C67A5 = { 122 | CreatedOnToolsVersion = 8.0; 123 | LastSwiftMigration = 1130; 124 | ProvisioningStyle = Automatic; 125 | }; 126 | }; 127 | }; 128 | buildConfigurationList = EB7D949A1DBD0CE5006C67A5 /* Build configuration list for PBXProject "Example" */; 129 | compatibilityVersion = "Xcode 3.2"; 130 | developmentRegion = en; 131 | hasScannedForEncodings = 0; 132 | knownRegions = ( 133 | en, 134 | Base, 135 | ); 136 | mainGroup = EB7D94961DBD0CE5006C67A5; 137 | productRefGroup = EB7D94A01DBD0CE5006C67A5 /* Products */; 138 | projectDirPath = ""; 139 | projectRoot = ""; 140 | targets = ( 141 | EB7D949E1DBD0CE5006C67A5 /* Example */, 142 | ); 143 | }; 144 | /* End PBXProject section */ 145 | 146 | /* Begin PBXResourcesBuildPhase section */ 147 | EB7D949D1DBD0CE5006C67A5 /* Resources */ = { 148 | isa = PBXResourcesBuildPhase; 149 | buildActionMask = 2147483647; 150 | files = ( 151 | EB7D94AA1DBD0CE5006C67A5 /* Assets.xcassets in Resources */, 152 | EB7D94A81DBD0CE5006C67A5 /* Main.storyboard in Resources */, 153 | ); 154 | runOnlyForDeploymentPostprocessing = 0; 155 | }; 156 | /* End PBXResourcesBuildPhase section */ 157 | 158 | /* Begin PBXShellScriptBuildPhase section */ 159 | 12D698F5CA00610B397B218C /* [CP] Embed Pods Frameworks */ = { 160 | isa = PBXShellScriptBuildPhase; 161 | buildActionMask = 2147483647; 162 | files = ( 163 | ); 164 | inputPaths = ( 165 | "${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-frameworks.sh", 166 | "${BUILT_PRODUCTS_DIR}/TvOSMoreButton/TvOSMoreButton.framework", 167 | "${BUILT_PRODUCTS_DIR}/TvOSTextViewer/TvOSTextViewer.framework", 168 | ); 169 | name = "[CP] Embed Pods Frameworks"; 170 | outputPaths = ( 171 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/TvOSMoreButton.framework", 172 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/TvOSTextViewer.framework", 173 | ); 174 | runOnlyForDeploymentPostprocessing = 0; 175 | shellPath = /bin/sh; 176 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-frameworks.sh\"\n"; 177 | showEnvVarsInLog = 0; 178 | }; 179 | ADF842CC42160071963C8C6D /* [CP] Check Pods Manifest.lock */ = { 180 | isa = PBXShellScriptBuildPhase; 181 | buildActionMask = 2147483647; 182 | files = ( 183 | ); 184 | inputPaths = ( 185 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 186 | "${PODS_ROOT}/Manifest.lock", 187 | ); 188 | name = "[CP] Check Pods Manifest.lock"; 189 | outputPaths = ( 190 | "$(DERIVED_FILE_DIR)/Pods-Example-checkManifestLockResult.txt", 191 | ); 192 | runOnlyForDeploymentPostprocessing = 0; 193 | shellPath = /bin/sh; 194 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 195 | showEnvVarsInLog = 0; 196 | }; 197 | EBEACC9E1E7159E60075CBD3 /* [Example] Linter */ = { 198 | isa = PBXShellScriptBuildPhase; 199 | buildActionMask = 2147483647; 200 | files = ( 201 | ); 202 | inputPaths = ( 203 | ); 204 | name = "[Example] Linter"; 205 | outputPaths = ( 206 | ); 207 | runOnlyForDeploymentPostprocessing = 0; 208 | shellPath = /bin/sh; 209 | shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; 210 | }; 211 | /* End PBXShellScriptBuildPhase section */ 212 | 213 | /* Begin PBXSourcesBuildPhase section */ 214 | EB7D949B1DBD0CE5006C67A5 /* Sources */ = { 215 | isa = PBXSourcesBuildPhase; 216 | buildActionMask = 2147483647; 217 | files = ( 218 | EB7D94A51DBD0CE5006C67A5 /* ViewController.swift in Sources */, 219 | EB7D94A31DBD0CE5006C67A5 /* AppDelegate.swift in Sources */, 220 | ); 221 | runOnlyForDeploymentPostprocessing = 0; 222 | }; 223 | /* End PBXSourcesBuildPhase section */ 224 | 225 | /* Begin PBXVariantGroup section */ 226 | EB7D94A61DBD0CE5006C67A5 /* Main.storyboard */ = { 227 | isa = PBXVariantGroup; 228 | children = ( 229 | EB7D94A71DBD0CE5006C67A5 /* Base */, 230 | ); 231 | name = Main.storyboard; 232 | sourceTree = ""; 233 | }; 234 | /* End PBXVariantGroup section */ 235 | 236 | /* Begin XCBuildConfiguration section */ 237 | EB7D94AC1DBD0CE5006C67A5 /* Debug */ = { 238 | isa = XCBuildConfiguration; 239 | buildSettings = { 240 | ALWAYS_SEARCH_USER_PATHS = NO; 241 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 242 | CLANG_ANALYZER_NONNULL = YES; 243 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 244 | CLANG_CXX_LIBRARY = "libc++"; 245 | CLANG_ENABLE_MODULES = YES; 246 | CLANG_ENABLE_OBJC_ARC = YES; 247 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 248 | CLANG_WARN_BOOL_CONVERSION = YES; 249 | CLANG_WARN_COMMA = YES; 250 | CLANG_WARN_CONSTANT_CONVERSION = YES; 251 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 252 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 253 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 254 | CLANG_WARN_EMPTY_BODY = YES; 255 | CLANG_WARN_ENUM_CONVERSION = YES; 256 | CLANG_WARN_INFINITE_RECURSION = YES; 257 | CLANG_WARN_INT_CONVERSION = YES; 258 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 259 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 260 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 261 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 262 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 263 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 264 | CLANG_WARN_STRICT_PROTOTYPES = YES; 265 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 266 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 267 | CLANG_WARN_UNREACHABLE_CODE = YES; 268 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 269 | COPY_PHASE_STRIP = NO; 270 | DEBUG_INFORMATION_FORMAT = dwarf; 271 | ENABLE_STRICT_OBJC_MSGSEND = YES; 272 | ENABLE_TESTABILITY = YES; 273 | GCC_C_LANGUAGE_STANDARD = gnu99; 274 | GCC_DYNAMIC_NO_PIC = NO; 275 | GCC_NO_COMMON_BLOCKS = YES; 276 | GCC_OPTIMIZATION_LEVEL = 0; 277 | GCC_PREPROCESSOR_DEFINITIONS = ( 278 | "DEBUG=1", 279 | "$(inherited)", 280 | ); 281 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 282 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 283 | GCC_WARN_UNDECLARED_SELECTOR = YES; 284 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 285 | GCC_WARN_UNUSED_FUNCTION = YES; 286 | GCC_WARN_UNUSED_VARIABLE = YES; 287 | MTL_ENABLE_DEBUG_INFO = YES; 288 | ONLY_ACTIVE_ARCH = YES; 289 | SDKROOT = appletvos; 290 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 291 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 292 | SWIFT_VERSION = 5.0; 293 | TARGETED_DEVICE_FAMILY = 3; 294 | TVOS_DEPLOYMENT_TARGET = 10.0; 295 | }; 296 | name = Debug; 297 | }; 298 | EB7D94AD1DBD0CE5006C67A5 /* Release */ = { 299 | isa = XCBuildConfiguration; 300 | buildSettings = { 301 | ALWAYS_SEARCH_USER_PATHS = NO; 302 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 303 | CLANG_ANALYZER_NONNULL = YES; 304 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 305 | CLANG_CXX_LIBRARY = "libc++"; 306 | CLANG_ENABLE_MODULES = YES; 307 | CLANG_ENABLE_OBJC_ARC = YES; 308 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 309 | CLANG_WARN_BOOL_CONVERSION = YES; 310 | CLANG_WARN_COMMA = YES; 311 | CLANG_WARN_CONSTANT_CONVERSION = YES; 312 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 313 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 314 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 315 | CLANG_WARN_EMPTY_BODY = YES; 316 | CLANG_WARN_ENUM_CONVERSION = YES; 317 | CLANG_WARN_INFINITE_RECURSION = YES; 318 | CLANG_WARN_INT_CONVERSION = YES; 319 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 320 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 321 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 322 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 323 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 324 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 325 | CLANG_WARN_STRICT_PROTOTYPES = YES; 326 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 327 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 328 | CLANG_WARN_UNREACHABLE_CODE = YES; 329 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 330 | COPY_PHASE_STRIP = NO; 331 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 332 | ENABLE_NS_ASSERTIONS = NO; 333 | ENABLE_STRICT_OBJC_MSGSEND = YES; 334 | GCC_C_LANGUAGE_STANDARD = gnu99; 335 | GCC_NO_COMMON_BLOCKS = YES; 336 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 337 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 338 | GCC_WARN_UNDECLARED_SELECTOR = YES; 339 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 340 | GCC_WARN_UNUSED_FUNCTION = YES; 341 | GCC_WARN_UNUSED_VARIABLE = YES; 342 | MTL_ENABLE_DEBUG_INFO = NO; 343 | SDKROOT = appletvos; 344 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 345 | SWIFT_VERSION = 5.0; 346 | TARGETED_DEVICE_FAMILY = 3; 347 | TVOS_DEPLOYMENT_TARGET = 10.0; 348 | VALIDATE_PRODUCT = YES; 349 | }; 350 | name = Release; 351 | }; 352 | EB7D94AF1DBD0CE5006C67A5 /* Debug */ = { 353 | isa = XCBuildConfiguration; 354 | baseConfigurationReference = B920AB125D1C037B3325EE4E /* Pods-Example.debug.xcconfig */; 355 | buildSettings = { 356 | ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; 357 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 358 | DEVELOPMENT_TEAM = ""; 359 | INFOPLIST_FILE = Example/Info.plist; 360 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 361 | PRODUCT_BUNDLE_IDENTIFIER = com.cgoldsby.Example; 362 | PRODUCT_NAME = "$(TARGET_NAME)"; 363 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 364 | SWIFT_VERSION = 5.0; 365 | }; 366 | name = Debug; 367 | }; 368 | EB7D94B01DBD0CE5006C67A5 /* Release */ = { 369 | isa = XCBuildConfiguration; 370 | baseConfigurationReference = 41A4C3646154EDDFA23FB6A3 /* Pods-Example.release.xcconfig */; 371 | buildSettings = { 372 | ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; 373 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 374 | DEVELOPMENT_TEAM = ""; 375 | INFOPLIST_FILE = Example/Info.plist; 376 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 377 | PRODUCT_BUNDLE_IDENTIFIER = com.cgoldsby.Example; 378 | PRODUCT_NAME = "$(TARGET_NAME)"; 379 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 380 | SWIFT_VERSION = 5.0; 381 | }; 382 | name = Release; 383 | }; 384 | /* End XCBuildConfiguration section */ 385 | 386 | /* Begin XCConfigurationList section */ 387 | EB7D949A1DBD0CE5006C67A5 /* Build configuration list for PBXProject "Example" */ = { 388 | isa = XCConfigurationList; 389 | buildConfigurations = ( 390 | EB7D94AC1DBD0CE5006C67A5 /* Debug */, 391 | EB7D94AD1DBD0CE5006C67A5 /* Release */, 392 | ); 393 | defaultConfigurationIsVisible = 0; 394 | defaultConfigurationName = Release; 395 | }; 396 | EB7D94AE1DBD0CE5006C67A5 /* Build configuration list for PBXNativeTarget "Example" */ = { 397 | isa = XCConfigurationList; 398 | buildConfigurations = ( 399 | EB7D94AF1DBD0CE5006C67A5 /* Debug */, 400 | EB7D94B01DBD0CE5006C67A5 /* Release */, 401 | ); 402 | defaultConfigurationIsVisible = 0; 403 | defaultConfigurationName = Release; 404 | }; 405 | /* End XCConfigurationList section */ 406 | }; 407 | rootObject = EB7D94971DBD0CE5006C67A5 /* Project object */; 408 | } 409 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /Example/Example.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/Example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // 4 | // Copyright (c) 2016-2019 Chris Goldsby 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import UIKit 26 | 27 | @UIApplicationMain 28 | class AppDelegate: UIResponder, UIApplicationDelegate { 29 | 30 | var window: UIWindow? 31 | 32 | // swiftlint:disable line_length 33 | func application(_ application: UIApplication, 34 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { 35 | return true 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "layers" : [ 3 | { 4 | "filename" : "Front.imagestacklayer" 5 | }, 6 | { 7 | "filename" : "Middle.imagestacklayer" 8 | }, 9 | { 10 | "filename" : "Back.imagestacklayer" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "layers" : [ 3 | { 4 | "filename" : "Front.imagestacklayer" 5 | }, 6 | { 7 | "filename" : "Middle.imagestacklayer" 8 | }, 9 | { 10 | "filename" : "Back.imagestacklayer" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "assets" : [ 3 | { 4 | "size" : "1280x768", 5 | "idiom" : "tv", 6 | "filename" : "App Icon - Large.imagestack", 7 | "role" : "primary-app-icon" 8 | }, 9 | { 10 | "size" : "400x240", 11 | "idiom" : "tv", 12 | "filename" : "App Icon - Small.imagestack", 13 | "role" : "primary-app-icon" 14 | }, 15 | { 16 | "size" : "2320x720", 17 | "idiom" : "tv", 18 | "filename" : "Top Shelf Image Wide.imageset", 19 | "role" : "top-shelf-image-wide" 20 | }, 21 | { 22 | "size" : "1920x720", 23 | "idiom" : "tv", 24 | "filename" : "Top Shelf Image.imageset", 25 | "role" : "top-shelf-image" 26 | } 27 | ], 28 | "info" : { 29 | "version" : 1, 30 | "author" : "xcode" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/Example/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/Example/background.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "background.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/Example/Assets.xcassets/Example/background.imageset/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Example/Example/Assets.xcassets/Example/background.imageset/background.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "landscape", 5 | "idiom" : "tv", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "9.0", 8 | "scale" : "1x" 9 | } 10 | ], 11 | "info" : { 12 | "version" : 1, 13 | "author" : "xcode" 14 | } 15 | } -------------------------------------------------------------------------------- /Example/Example/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 54 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /Example/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 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIMainStoryboardFile 24 | Main 25 | UIRequiredDeviceCapabilities 26 | 27 | arm64 28 | 29 | UIUserInterfaceStyle 30 | Automatic 31 | 32 | 33 | -------------------------------------------------------------------------------- /Example/Example/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // 4 | // Copyright (c) 2016-2019 Chris Goldsby 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import UIKit 26 | import TvOSMoreButton 27 | import TvOSTextViewer 28 | 29 | final class ViewController: UIViewController { 30 | 31 | @IBOutlet private weak var tvOSMoreButton: TvOSMoreButton! 32 | 33 | override func viewDidLoad() { 34 | super.viewDidLoad() 35 | setUpUI() 36 | } 37 | 38 | // MARK: - Private 39 | 40 | private func setUpUI() { 41 | tvOSMoreButton.text = "It is the year 1985. Marty McFly, a mild-mannered high school student, stopped by Dr. Emmett L. Brown's laboratory to play around with an amplifier. Then he receives a message from Doc that he needs help from him for Doc's latest invention, a time machine made out of a DeLorean sports car that can travel through time instantaneously when it reaches a speed velocity of 88 MPH. Then, Doc was gunned down by Libyan Nationalists, Marty makes an effort to escape from the Lybians by using the time machine. Then Marty accidentally warps himself into 1955. Where he meets both of his parents when they were teenagers, then Marty unintentionally interrupts his parent's first meeting together, he then finds a younger version of Doc and together they try to find a way to get Marty's parents-to-be back together, and to get Marty back to 1985." 42 | tvOSMoreButton.buttonWasPressed = { 43 | [weak self] text in 44 | self?.moreButtonWasPressed(text: text) 45 | } 46 | } 47 | 48 | private func moreButtonWasPressed(text: String?) { 49 | guard let text = text else { return } 50 | let viewController = TvOSTextViewerViewController() 51 | viewController.text = text 52 | viewController.textEdgeInsets = UIEdgeInsets(top: 100, left: 250, bottom: 100, right: 250) 53 | present(viewController, animated: true) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | platform :tvos, '9.0' 4 | 5 | target 'Example' do 6 | use_frameworks! 7 | pod 'TvOSMoreButton', path: '..' 8 | pod 'TvOSTextViewer' 9 | end 10 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - TvOSMoreButton (1.3.0) 3 | - TvOSTextViewer (1.2.0) 4 | 5 | DEPENDENCIES: 6 | - TvOSMoreButton (from `..`) 7 | - TvOSTextViewer 8 | 9 | SPEC REPOS: 10 | https://cocoapods-cdn.netlify.app/: 11 | - TvOSTextViewer 12 | 13 | EXTERNAL SOURCES: 14 | TvOSMoreButton: 15 | :path: ".." 16 | 17 | SPEC CHECKSUMS: 18 | TvOSMoreButton: 293f34e3db5e4e8876ccb110632b40f9318dec7d 19 | TvOSTextViewer: a8403c9a7a312e6fe3b18b7e82839e7d8697a326 20 | 21 | PODFILE CHECKSUM: eb741d973e05673c74cdf9fd62b4a7e18f29a05f 22 | 23 | COCOAPODS: 1.8.4 24 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem 'cocoapods', '~> 1.8.4' 4 | 5 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.2) 5 | activesupport (4.2.11.1) 6 | i18n (~> 0.7) 7 | minitest (~> 5.1) 8 | thread_safe (~> 0.3, >= 0.3.4) 9 | tzinfo (~> 1.1) 10 | algoliasearch (1.27.1) 11 | httpclient (~> 2.8, >= 2.8.3) 12 | json (>= 1.5.1) 13 | atomos (0.1.3) 14 | claide (1.0.3) 15 | cocoapods (1.8.4) 16 | activesupport (>= 4.0.2, < 5) 17 | claide (>= 1.0.2, < 2.0) 18 | cocoapods-core (= 1.8.4) 19 | cocoapods-deintegrate (>= 1.0.3, < 2.0) 20 | cocoapods-downloader (>= 1.2.2, < 2.0) 21 | cocoapods-plugins (>= 1.0.0, < 2.0) 22 | cocoapods-search (>= 1.0.0, < 2.0) 23 | cocoapods-stats (>= 1.0.0, < 2.0) 24 | cocoapods-trunk (>= 1.4.0, < 2.0) 25 | cocoapods-try (>= 1.1.0, < 2.0) 26 | colored2 (~> 3.1) 27 | escape (~> 0.0.4) 28 | fourflusher (>= 2.3.0, < 3.0) 29 | gh_inspector (~> 1.0) 30 | molinillo (~> 0.6.6) 31 | nap (~> 1.0) 32 | ruby-macho (~> 1.4) 33 | xcodeproj (>= 1.11.1, < 2.0) 34 | cocoapods-core (1.8.4) 35 | activesupport (>= 4.0.2, < 6) 36 | algoliasearch (~> 1.0) 37 | concurrent-ruby (~> 1.1) 38 | fuzzy_match (~> 2.0.4) 39 | nap (~> 1.0) 40 | cocoapods-deintegrate (1.0.4) 41 | cocoapods-downloader (1.6.3) 42 | cocoapods-plugins (1.0.0) 43 | nap 44 | cocoapods-search (1.0.0) 45 | cocoapods-stats (1.1.0) 46 | cocoapods-trunk (1.4.1) 47 | nap (>= 0.8, < 2.0) 48 | netrc (~> 0.11) 49 | cocoapods-try (1.1.0) 50 | colored2 (3.1.2) 51 | concurrent-ruby (1.1.5) 52 | escape (0.0.4) 53 | fourflusher (2.3.1) 54 | fuzzy_match (2.0.4) 55 | gh_inspector (1.1.3) 56 | httpclient (2.8.3) 57 | i18n (0.9.5) 58 | concurrent-ruby (~> 1.0) 59 | json (2.3.1) 60 | minitest (5.13.0) 61 | molinillo (0.6.6) 62 | nanaimo (0.2.6) 63 | nap (1.1.0) 64 | netrc (0.11.0) 65 | ruby-macho (1.4.0) 66 | thread_safe (0.3.6) 67 | tzinfo (1.2.10) 68 | thread_safe (~> 0.1) 69 | xcodeproj (1.14.0) 70 | CFPropertyList (>= 2.3.3, < 4.0) 71 | atomos (~> 0.1.3) 72 | claide (>= 1.0.2, < 2.0) 73 | colored2 (~> 3.1) 74 | nanaimo (~> 0.2.6) 75 | 76 | PLATFORMS 77 | ruby 78 | 79 | DEPENDENCIES 80 | cocoapods (~> 1.8.4) 81 | 82 | BUNDLED WITH 83 | 2.0.2 84 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2017 Chris Goldsby 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "SnapshotTesting", 6 | "repositoryURL": "https://github.com/pointfreeco/swift-snapshot-testing.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "c466812aa2e22898f27557e2e780d3aad7a27203", 10 | "version": "1.8.2" 11 | } 12 | } 13 | ] 14 | }, 15 | "version": 1 16 | } 17 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "TvOSMoreButton", 7 | platforms: [ 8 | .tvOS(.v10) 9 | ], 10 | products: [ 11 | // Products define the executables and libraries a package produces, and make them visible to other packages. 12 | .library( 13 | name: "TvOSMoreButton", 14 | targets: ["TvOSMoreButton"]) 15 | ], 16 | dependencies: [ 17 | .package(name: "SnapshotTesting", url: "https://github.com/pointfreeco/swift-snapshot-testing.git", from: "1.8.1") 18 | ], 19 | targets: [ 20 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 21 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 22 | .target( 23 | name: "TvOSMoreButton", 24 | dependencies: [ 25 | ], 26 | path: "Source", 27 | exclude: ["../Artwork", "../Example", "Info.plist"], 28 | resources: [ 29 | .process("../Resources") 30 | ] 31 | ), 32 | .testTarget( 33 | name: "TvOSMoreButtonTests", 34 | dependencies: ["TvOSMoreButton", "SnapshotTesting"], 35 | path: "Tests", 36 | exclude: ["Info.plist"], 37 | resources: [ 38 | .process("Public/Views/__Snapshots__/Tests_TvOSMoreButton"), 39 | .process("Resources/Localizable.strings") 40 | ] 41 | ) 42 | ] 43 | ) 44 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | platform :tvos, '10.0' 4 | 5 | target 'UnitTests' do 6 | use_frameworks! 7 | pod 'SnapshotTesting', '~> 1.8.2' 8 | pod 'SwiftLint', '~> 0.27.0' 9 | end 10 | 11 | post_install do |installer| 12 | # This removes the warning about last conversion 13 | last_xcode_version_check = 1320 # Last check is Xcode 13.2 14 | installer.pods_project.root_object.attributes['LastSwiftMigration'] = last_xcode_version_check 15 | installer.pods_project.root_object.attributes['LastSwiftUpdateCheck'] = last_xcode_version_check 16 | installer.pods_project.root_object.attributes['LastUpgradeCheck'] = last_xcode_version_check 17 | 18 | shared_data_dir = Xcodeproj::XCScheme.user_data_dir(installer.pods_project.path) 19 | Dir["#{shared_data_dir}/*.xcscheme"].each do |scheme_path| 20 | scheme = Xcodeproj::XCScheme.new scheme_path 21 | scheme.doc.root.attributes['LastUpgradeVersion'] = last_xcode_version_check 22 | scheme.save! 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - SnapshotTesting (1.8.2) 3 | - SwiftLint (0.27.0) 4 | 5 | DEPENDENCIES: 6 | - SnapshotTesting (~> 1.8.2) 7 | - SwiftLint (~> 0.27.0) 8 | 9 | SPEC REPOS: 10 | trunk: 11 | - SnapshotTesting 12 | - SwiftLint 13 | 14 | SPEC CHECKSUMS: 15 | SnapshotTesting: 38947050d13960d57a4a9c166fcf51bca7d56970 16 | SwiftLint: 3207c1faa2240bf8973b191820a116113cd11073 17 | 18 | PODFILE CHECKSUM: b6ff737bac7475fdd0fb7aac90fdd7da53629c38 19 | 20 | COCOAPODS: 1.8.4 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TvOSMoreButton 2 | > 📺 A tvOS button which truncates long text with '... More'. 3 | 4 | The TvOSMoreButton is a simple view which aims to mirror the behavior of Apple's "... More" button; as seen in the Movie App. 5 | 6 | ![](Artwork/example.png) 7 | 8 | ## Features 9 | 10 | If the text is too long to fit with in the button bounds then the text will be truncated and '... More' will be appended. 11 | 12 | By default, if the text is truncated the button will be focusable. If the text is not truncated then the button will not be focusable. 13 | 14 | However, you can set `focusableMode` to `manual(_ isFocusable: Bool)` to alter the focus behavior. This mode will force the button to be always be focused or never be focused. 15 | 16 | When the button is focused, pressing select on the Apple TV remote will trigger a callback. 17 | 18 | The majority of the UI properties are configurable; like 19 | - the button text 20 | - ellipse text; defaults to '...' 21 | - trailing text; defaults to "More" 22 | - trailing text color and font 23 | - the button text color and font 24 | - shadows and radius 25 | - and More 😉 26 | 27 | ## Requirements 28 | 29 | - tvOS 9.0+ 30 | - Xcode 9 31 | 32 | ## Installation 33 | 34 | #### CocoaPods 35 | [CocoaPods](https://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command: 36 | 37 | ``` 38 | $ gem install cocoapods 39 | ``` 40 | 41 | To integrate TvOSMoreButton into your Xcode project using CocoaPods, specify it in your Podfile: 42 | 43 | 44 | ```ruby 45 | source 'https://github.com/CocoaPods/Specs.git' 46 | platform :tvos, '9.0' 47 | use_frameworks! 48 | 49 | target '' do 50 | pod 'TvOSMoreButton', '~> 1.4.1' 51 | end 52 | ``` 53 | 54 | Then, run the following command: 55 | 56 | ``` 57 | $ pod install 58 | ``` 59 | 60 | ### Carthage 61 | 62 | [Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. 63 | 64 | You can install Carthage with Homebrew using the following command: 65 | 66 | ``` 67 | $ brew update 68 | $ brew install carthage 69 | ``` 70 | 71 | To integrate TvOSMoreButton into your Xcode project using Carthage, specify it in your Cartfile: 72 | 73 | ``` 74 | github "cgoldsby/TvOSMoreButton" ~> 1.4.1 75 | ``` 76 | 77 | Run `carthage update` to build the framework and drag the built TvOSMoreButton.framework into your Xcode project. 78 | 79 | ## Usage example 80 | 81 | Please check out the Example workspace for more details. 82 | 83 | ```swift 84 | import TvOSMoreButton 85 | 86 | private func setUpUI() { 87 | tvOSMoreButton.text = // Super long text 88 | tvOSMoreButton.buttonWasPressed = { 89 | [weak self] text in 90 | self?.moreButtonWasPressed(text: text) 91 | } 92 | } 93 | 94 | private func moreButtonWasPressed(text: String?) -> Void { 95 | // Do something. May I suggest using TvOSTextViewerViewController 96 | // to display the text in a full screen view! 97 | let viewController = TvOSTextViewerViewController() 98 | viewController.text = text 99 | viewController.textColor = .white 100 | viewController.textEdgeInsets = UIEdgeInsets(top: 100, left: 250, bottom: 100, right: 250) 101 | present(viewController, animated: true) 102 | } 103 | 104 | ``` 105 | 106 | If you would like to display a fullscreen view with just the text then definitely check out [@dcordero](https://github.com/dcordero)'s awesome [TvOSTextViewer](https://github.com/dcordero/TvOSTextViewer). So good! 107 | 108 | ## Contribute 109 | 110 | We would love for you to contribute to **TvOSMoreButton**, check the ``LICENSE`` file for more info. Feel free to submit any issues or PRs. ❤️ 111 | 112 | ## Meta 113 | 114 | Special thanks [@mona-zsh](https://github.com/mona-zsh) for her fantastic article on [String Truncation](http://eskimona.com/coding/objective-c/2015/05/10/truncation.html). 115 | 116 | Chris Goldsby – [@goldsbychris](https://twitter.com/goldsbychris) 117 | 118 | Distributed under the MIT license. See ``LICENSE`` for more information. 119 | -------------------------------------------------------------------------------- /Resources/de.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | TvOSMoreButton 4 | 5 | Created by Christopher Goldsby on 10/20/16. 6 | Copyright © 2016 Christopher Goldsby. All rights reserved. 7 | */ 8 | 9 | /* Text that appears after a long description in a label */ 10 | "TvOSMoreButton.More.Text" = "Mehr"; 11 | -------------------------------------------------------------------------------- /Resources/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | TvOSMoreButton 4 | 5 | Created by Christopher Goldsby on 10/20/16. 6 | Copyright © 2016 Christopher Goldsby. All rights reserved. 7 | */ 8 | 9 | /* Text that appears after a long description in a label */ 10 | "TvOSMoreButton.More.Text" = "More"; 11 | -------------------------------------------------------------------------------- /Resources/es-MX.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | TvOSMoreButton 4 | 5 | Created by Christopher Goldsby on 10/20/16. 6 | Copyright © 2016 Christopher Goldsby. All rights reserved. 7 | */ 8 | 9 | /* Text that appears after a long description in a label */ 10 | "TvOSMoreButton.More.Text" = "Más"; 11 | -------------------------------------------------------------------------------- /Resources/es.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | TvOSMoreButton 4 | 5 | Created by Christopher Goldsby on 10/20/16. 6 | Copyright © 2016 Christopher Goldsby. All rights reserved. 7 | */ 8 | 9 | /* Text that appears after a long description in a label */ 10 | "TvOSMoreButton.More.Text" = "Más"; 11 | -------------------------------------------------------------------------------- /Resources/fr.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | TvOSMoreButton 4 | 5 | Created by Christopher Goldsby on 10/20/16. 6 | Copyright © 2016 Christopher Goldsby. All rights reserved. 7 | */ 8 | 9 | /* Text that appears after a long description in a label */ 10 | "TvOSMoreButton.More.Text" = "Plus"; 11 | -------------------------------------------------------------------------------- /Resources/it.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | TvOSMoreButton 4 | 5 | Created by Christopher Goldsby on 10/20/16. 6 | Copyright © 2016 Christopher Goldsby. All rights reserved. 7 | */ 8 | 9 | /* Text that appears after a long description in a label */ 10 | "TvOSMoreButton.More.Text" = "Altro"; 11 | -------------------------------------------------------------------------------- /Resources/ja.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | TvOSMoreButton 4 | 5 | Created by Christopher Goldsby on 10/20/16. 6 | Copyright © 2016 Christopher Goldsby. All rights reserved. 7 | */ 8 | 9 | /* Text that appears after a long description in a label */ 10 | "TvOSMoreButton.More.Text" = "もっと"; 11 | -------------------------------------------------------------------------------- /Resources/nb.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | TvOSMoreButton 4 | 5 | Created by Christopher Goldsby on 10/20/16. 6 | Copyright © 2016 Christopher Goldsby. All rights reserved. 7 | */ 8 | 9 | /* Text that appears after a long description in a label */ 10 | "TvOSMoreButton.More.Text" = "Mer"; 11 | -------------------------------------------------------------------------------- /Resources/nl.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | TvOSMoreButton 4 | 5 | Created by Christopher Goldsby on 10/20/16. 6 | Copyright © 2016 Christopher Goldsby. All rights reserved. 7 | */ 8 | 9 | /* Text that appears after a long description in a label */ 10 | "TvOSMoreButton.More.Text" = "Meer"; 11 | -------------------------------------------------------------------------------- /Resources/ru.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | TvOSMoreButton 4 | 5 | Created by Christopher Goldsby on 10/20/16. 6 | Copyright © 2016 Christopher Goldsby. All rights reserved. 7 | */ 8 | 9 | /* Text that appears after a long description in a label */ 10 | "TvOSMoreButton.More.Text" = "Больше"; 11 | -------------------------------------------------------------------------------- /Source/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Source/Private/Helpers/BundleLoader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BundleLoader.swift 3 | // 4 | // Copyright (c) 2016-2019 Chris Goldsby 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | var localizedStringBundle = Bundle.main 28 | 29 | final class BundleLoader { 30 | 31 | static let main: Bundle = { 32 | let podBundle = Bundle(for: BundleLoader.self) 33 | 34 | guard let url = podBundle.url(forResource: String(describing: TvOSMoreButton.self), withExtension: "bundle"), 35 | let resourceBundle = Bundle(url: url) else { return localizedStringBundle } 36 | 37 | if let language = Locale.current.languageCode, 38 | let url = resourceBundle.path(forResource: language, ofType: "lproj"), 39 | let bundle = Bundle(path: url) { 40 | return bundle 41 | } 42 | else if let url = resourceBundle.path(forResource: "en", ofType: "lproj"), 43 | let bundle = Bundle(path: url) { 44 | return bundle 45 | } 46 | else { 47 | return localizedStringBundle 48 | } 49 | }() 50 | } 51 | -------------------------------------------------------------------------------- /Source/Private/Helpers/LocalizedStrings.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LocalizedStrings.swift 3 | // 4 | // Copyright (c) 2016-2019 Chris Goldsby 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | extension String { 28 | 29 | enum TvOSMoreButton { 30 | case ellipses 31 | case more 32 | 33 | var 🌍: String { 34 | switch self { 35 | case .ellipses: 36 | return "…" 37 | case .more: 38 | return NSLocalizedString( 39 | "TvOSMoreButton.More.Text", 40 | bundle: BundleLoader.main, 41 | comment: "Text that appears after a long description in a label." 42 | ).uppercased() 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Source/Private/Helpers/String+Truncation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+Truncation.swift 3 | // 4 | // Copyright (c) 2016-2019 Chris Goldsby 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | import CoreGraphics 27 | import UIKit 28 | 29 | extension String { 30 | 31 | func truncateToSize(size: CGSize, 32 | ellipsesString: String, 33 | trailingText: String, 34 | attributes: [NSAttributedString.Key: Any], 35 | trailingTextAttributes: [NSAttributedString.Key: Any]) -> NSAttributedString { 36 | 37 | if !willFit(to: size, 38 | attributes: attributes, 39 | trailingTextAttributes: trailingTextAttributes) { 40 | 41 | let indexOfLastCharacterThatFits = indexThatFits(size: size, 42 | ellipsesString: ellipsesString, 43 | trailingText: trailingText, 44 | attributes: attributes, 45 | trailingTextAttributes: trailingTextAttributes, 46 | minIndex: 0, 47 | maxIndex: count) 48 | 49 | let range = startIndex.. Bool { 67 | 68 | var trailingTextAttributes = trailingTextAttributes 69 | if let textFont = attributes[.font] as? UIFont, 70 | let trailingTextFont = trailingTextAttributes[.font] as? UIFont, 71 | trailingTextFont.lineHeight < textFont.lineHeight { 72 | trailingTextAttributes[.font] = textFont 73 | } 74 | 75 | let attributedString = NSMutableAttributedString(string: self + ellipsesString, attributes: attributes) 76 | let attributedTrailingString = NSAttributedString(string: trailingText, attributes: trailingTextAttributes) 77 | attributedString.append(attributedTrailingString) 78 | 79 | let boundedSize = CGSize(width: size.width, height: .greatestFiniteMagnitude) 80 | let options: NSStringDrawingOptions = [.usesLineFragmentOrigin, .usesFontLeading] 81 | let boundedRect = attributedString.boundingRect(with: boundedSize, 82 | options: options, 83 | context: nil) 84 | return boundedRect.height <= size.height 85 | } 86 | 87 | // MARK: - Private 88 | 89 | private func indexThatFits(size: CGSize, 90 | ellipsesString: String, 91 | trailingText: String, 92 | attributes: [NSAttributedString.Key: Any], 93 | trailingTextAttributes: [NSAttributedString.Key: Any], 94 | minIndex: Int, 95 | maxIndex: Int) -> Int { 96 | 97 | guard maxIndex - minIndex != 1 else { return minIndex } 98 | 99 | let midIndex = (minIndex + maxIndex) / 2 100 | let range = startIndex.. Void)? 140 | 141 | private var textAttributes: [NSAttributedString.Key: Any] { 142 | return [ 143 | .foregroundColor: textColor, 144 | .font: font 145 | ] 146 | } 147 | 148 | private var trailingTextAttributes: [NSAttributedString.Key: Any] { 149 | return [ 150 | .foregroundColor: trailingTextColor, 151 | .font: trailingTextFont 152 | ] 153 | } 154 | 155 | public override init(frame: CGRect) { 156 | super.init(frame: frame) 157 | setUpUI() 158 | } 159 | 160 | public required init?(coder aDecoder: NSCoder) { 161 | super.init(coder: aDecoder) 162 | setUpUI() 163 | } 164 | 165 | override open var intrinsicContentSize: CGSize { 166 | return label.intrinsicContentSize 167 | } 168 | 169 | override open var canBecomeFocused: Bool { 170 | return isFocusable 171 | } 172 | 173 | override open func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) { 174 | coordinator.addCoordinatedAnimations({ 175 | self.isFocused ? self.applyFocusedAppearance() : self.applyUnfocusedAppearance() 176 | }) 177 | } 178 | 179 | open func updateUI() { 180 | truncateAndUpdateText() 181 | } 182 | 183 | // MARK: - Presses 184 | 185 | override open func pressesBegan(_ presses: Set, with event: UIPressesEvent?) { 186 | super.pressesBegan(presses, with: event) 187 | for item in presses where item.type == .select { 188 | applyPressDownAppearance() 189 | } 190 | } 191 | 192 | override open func pressesEnded(_ presses: Set, with event: UIPressesEvent?) { 193 | super.pressesEnded(presses, with: event) 194 | for item in presses where item.type == .select { 195 | applyPressUpAppearance() 196 | } 197 | } 198 | 199 | override open func pressesCancelled(_ presses: Set, with event: UIPressesEvent?) { 200 | for item in presses where item.type == .select { 201 | applyPressUpAppearance() 202 | } 203 | } 204 | 205 | // MARK: - Private 206 | 207 | private func setUpUI() { 208 | setUpView() 209 | setUpFocusedView() 210 | setUpContentView() 211 | setUpLabel() 212 | setUpSelectGestureRecognizer() 213 | applyUnfocusedAppearance() 214 | } 215 | 216 | private func setUpView() { 217 | isUserInteractionEnabled = true 218 | backgroundColor = .clear 219 | clipsToBounds = false 220 | isAccessibilityElement = true 221 | accessibilityTraits = UIAccessibilityTraits.button 222 | accessibilityIdentifier = "tvos more button" 223 | } 224 | 225 | private func setUpContentView() { 226 | addSubview(contentView) 227 | contentView.pinToSuperview(insets: contentInset) 228 | } 229 | 230 | private func setUpLabel() { 231 | label = UILabel(frame: bounds) 232 | label.numberOfLines = 0 233 | contentView.addSubview(label) 234 | label.pinToSuperview() 235 | } 236 | 237 | private func setUpFocusedView() { 238 | focusedView = UIView(frame: bounds) 239 | focusedView.layer.cornerRadius = cornerRadius 240 | focusedView.layer.shadowColor = shadowColor 241 | focusedView.layer.shadowRadius = shadowRadius 242 | 243 | addSubview(focusedView) 244 | focusedView.pinToSuperview() 245 | 246 | let blurEffect = UIBlurEffect(style: .light) 247 | let blurredView = UIVisualEffectView(effect: blurEffect) 248 | blurredView.frame = bounds 249 | blurredView.alpha = focusedViewAlpha 250 | blurredView.layer.cornerRadius = cornerRadius 251 | blurredView.layer.masksToBounds = true 252 | 253 | focusedView.addSubview(blurredView) 254 | blurredView.pinToSuperview() 255 | } 256 | 257 | private func setUpSelectGestureRecognizer() { 258 | selectGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(selectGestureWasPressed)) 259 | selectGestureRecognizer.allowedPressTypes = [NSNumber(value: UIPress.PressType.select.rawValue)] 260 | addGestureRecognizer(selectGestureRecognizer) 261 | } 262 | 263 | @objc private func selectGestureWasPressed() { 264 | buttonWasPressed?(text) 265 | } 266 | 267 | // MARK: - Focus Appearance 268 | 269 | func applyFocusedAppearance() { 270 | transform = CGAffineTransform(scaleX: focusedScaleFactor, y: focusedScaleFactor) 271 | focusedView.layer.shadowOffset = focusedShadowOffset 272 | focusedView.layer.shadowOpacity = focusedShadowOpacity 273 | focusedView.alpha = 1 274 | } 275 | 276 | func applyUnfocusedAppearance() { 277 | transform = CGAffineTransform.identity 278 | focusedView.layer.shadowOffset = .zero 279 | focusedView.layer.shadowOpacity = 0 280 | focusedView.alpha = 0 281 | } 282 | 283 | private func applyPressUpAppearance() { 284 | UIView.animate(withDuration: pressAnimationDuration) { 285 | self.isFocused ? self.applyFocusedAppearance() : self.applyUnfocusedAppearance() 286 | } 287 | } 288 | 289 | private func applyPressDownAppearance() { 290 | UIView.animate(withDuration: pressAnimationDuration) { 291 | self.transform = CGAffineTransform.identity 292 | self.focusedView.layer.shadowOffset = .zero 293 | self.focusedView.layer.shadowOpacity = 0 294 | } 295 | } 296 | 297 | // MARK: - Truncating Text 298 | 299 | private func truncateAndUpdateText() { 300 | label.text = text 301 | accessibilityLabel = text 302 | 303 | guard let text = text, !text.isEmpty else { return } 304 | 305 | layoutIfNeeded() 306 | let labelSize = label.bounds.size 307 | let trailingText = " " + self.trailingText 308 | label.attributedText = text.truncateToSize(size: labelSize, 309 | ellipsesString: ellipsesString, 310 | trailingText: trailingText, 311 | attributes: textAttributes, 312 | trailingTextAttributes: trailingTextAttributes) 313 | accessibilityLabel = label.attributedText?.string 314 | 315 | if case .auto = focusableMode { 316 | isFocusable = !text.willFit(to: labelSize, 317 | attributes: textAttributes, 318 | trailingTextAttributes: trailingTextAttributes) 319 | } 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /Source/TvOSMoreButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // TvOSMoreButton.h 3 | // 4 | // Copyright (c) 2016-2019 Chris Goldsby 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | @import UIKit; 26 | 27 | FOUNDATION_EXPORT double TvOSMoreButtonVersionNumber; 28 | 29 | FOUNDATION_EXPORT const unsigned char TvOSMoreButtonVersionString[]; 30 | -------------------------------------------------------------------------------- /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 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tests/Public/Views/Tests_TvOSMoreButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Tests_TvOSMoreButton.swift 3 | // 4 | // Copyright (c) 2016-2019 Chris Goldsby 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import SnapshotTesting 26 | import XCTest 27 | @testable import TvOSMoreButton 28 | 29 | // swiftlint:disable type_name 30 | final class Tests_TvOSMoreButton: XCTestCase { 31 | // swiftlint:enable type_name 32 | 33 | private var sut: TvOSMoreButton! 34 | 35 | override func setUp() { 36 | super.setUp() 37 | localizedStringBundle = .testBundle() 38 | let frame = CGRect(x: 0, y: 0, width: 500, height: 100) 39 | sut = TvOSMoreButton(frame: frame) 40 | isRecording = false 41 | } 42 | 43 | override func tearDown() { 44 | super.tearDown() 45 | localizedStringBundle = .main 46 | } 47 | 48 | func test_that_button_with_text_that_fits_and_focused_mode_auto_can_not_become_focused() { 49 | // Given 50 | precondition(sut.focusableMode == .auto) 51 | 52 | // When 53 | sut.text = textThatFits 54 | 55 | // Then 56 | XCTAssertFalse(sut.canBecomeFocused) 57 | } 58 | 59 | func test_that_button_with_truncated_text_and_focused_mode_auto_can_become_focused() { 60 | // Given 61 | precondition(sut.focusableMode == .auto) 62 | 63 | // When 64 | sut.text = longText 65 | 66 | // Then 67 | XCTAssertTrue(sut.canBecomeFocused) 68 | } 69 | 70 | func test_that_button_with_text_that_fits_and_focused_mode_manual_can_become_focused() { 71 | // When 72 | sut.text = textThatFits 73 | sut.focusableMode = .manual(true) 74 | 75 | // Then 76 | XCTAssertTrue(sut.canBecomeFocused) 77 | } 78 | 79 | func test_that_button_with_truncated_text_and_focused_mode_manual_can_not_become_focused() { 80 | // When 81 | sut.text = longText 82 | sut.focusableMode = .manual(false) 83 | 84 | // Then 85 | XCTAssertFalse(sut.canBecomeFocused) 86 | } 87 | 88 | func test_that_button_with_truncated_text_can_be_come_focused_when_chaning_focus_mode_to_auto() { 89 | // Given 90 | sut.focusableMode = .manual(false) 91 | precondition(!sut.canBecomeFocused) 92 | 93 | // When 94 | sut.text = longText 95 | sut.focusableMode = .auto 96 | 97 | // Then 98 | XCTAssertTrue(sut.canBecomeFocused) 99 | } 100 | 101 | // MARK: - Snapshots 102 | 103 | func test_that_unfocused_button_with_text_that_fits_renders_correctly() { 104 | // When 105 | sut.text = textThatFits 106 | 107 | // Then 108 | 📸(sut) 109 | } 110 | 111 | func test_that_unfocused_button_with_truncated_text_renders_correctly() { 112 | // When 113 | sut.text = longText 114 | 115 | // Then 116 | 📸(sut) 117 | } 118 | 119 | func test_that_unfocused_button_with_text_that_fits_and_custom_text_color_renders_correctly() { 120 | // Given 121 | let customTextColor = UIColor.yellow 122 | 123 | // When 124 | sut.text = textThatFits 125 | sut.textColor = customTextColor 126 | 127 | // Then 128 | 📸(sut) 129 | } 130 | 131 | func test_that_unfocused_button_with_truncated_text_and_and_custom_text_color_renders_correctly() { 132 | // Given 133 | let customTextColor = UIColor.yellow 134 | 135 | // When 136 | sut.text = longText 137 | sut.textColor = customTextColor 138 | 139 | // Then 140 | 📸(sut) 141 | } 142 | 143 | func test_that_unfocused_button_with_text_that_fits_and_custom_font_renders_correctly() { 144 | // Given 145 | let textThatFits = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eius." 146 | let currentFont = sut.font 147 | let customFont = UIFont(name: "AmericanTypewriter", size: currentFont.pointSize)! 148 | 149 | // When 150 | sut.text = textThatFits 151 | sut.font = customFont 152 | 153 | // Then 154 | 📸(sut) 155 | } 156 | 157 | func test_that_unfocused_button_with_truncated_text_and_custom_font_renders_correctly() { 158 | // Given 159 | let currentFont = sut.font 160 | let customFont = UIFont(name: "AmericanTypewriter", size: currentFont.pointSize)! 161 | 162 | // When 163 | sut.text = longText 164 | sut.font = customFont 165 | 166 | // Then 167 | 📸(sut) 168 | } 169 | 170 | func test_that_unfocused_button_with_truncated_text_and_custom_trailing_text_font_renders_correctly() { 171 | // Given 172 | let currentFont = sut.trailingTextFont 173 | let customFont = UIFont(name: "AmericanTypewriter-Bold", size: currentFont.pointSize)! 174 | 175 | // When 176 | sut.text = longText 177 | sut.trailingTextFont = customFont 178 | 179 | // Then 180 | 📸(sut) 181 | } 182 | 183 | func test_that_unfocused_button_with_truncated_text_and_custom_trailing_text_color_renders_correctly() { 184 | // Given 185 | let customTrailingTextColor = UIColor.yellow 186 | 187 | // When 188 | sut.text = longText 189 | sut.trailingTextColor = customTrailingTextColor 190 | 191 | // Then 192 | 📸(sut) 193 | } 194 | 195 | func test_that_unfocused_button_with_truncated_text_and_custom_trailing_text_renders_correctly() { 196 | // Given 197 | let customTrailingText = "🚜" 198 | 199 | // When 200 | sut.text = longText 201 | sut.trailingText = customTrailingText 202 | 203 | // Then 204 | 📸(sut) 205 | } 206 | 207 | func test_that_unfocused_button_with_truncated_text_and_custom_ellipses_string_renders_correctly() { 208 | // Given 209 | let customEllipsesString = " → " 210 | 211 | // When 212 | sut.text = longText 213 | sut.ellipsesString = customEllipsesString 214 | 215 | // Then 216 | 📸(sut) 217 | } 218 | 219 | func test_that_unfocused_button_with_text_that_fits_and_custom_text_alignment_renders_correctly() { 220 | // Given 221 | let customTextAlignment = NSTextAlignment.right 222 | 223 | // When 224 | sut.text = textThatFits 225 | sut.textAlignment = customTextAlignment 226 | 227 | // Then 228 | 📸(sut) 229 | } 230 | 231 | func test_that_unfocused_button_with_truncated_text_and_custom_text_alignment_renders_correctly() { 232 | // Given 233 | let customTextAlignment = NSTextAlignment.right 234 | 235 | // When 236 | sut.text = longText 237 | sut.textAlignment = customTextAlignment 238 | 239 | // Then 240 | 📸(sut) 241 | } 242 | 243 | func test_that_focused_button_with_truncated_text_renders_correctly() { 244 | // When 245 | sut.text = longText 246 | sut.applyFocusedAppearance() 247 | 248 | // Then 249 | 📸(sut) 250 | } 251 | 252 | func test_that_button_with_truncated_text_has_unfocused_appearance_after_being_focused() { 253 | // Given 254 | sut.text = longText 255 | sut.applyFocusedAppearance() 256 | 257 | // When 258 | sut.applyUnfocusedAppearance() 259 | 260 | // Then 261 | 📸(sut) 262 | } 263 | 264 | func test_that_unfocused_button_with_text_that_fits_and_custom_content_inset_renders_correctly() { 265 | // Given 266 | let customContentInset = UIEdgeInsets(top: 20, left: 35, bottom: 20, right: 35) 267 | let textThatFits = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do." 268 | 269 | // When 270 | sut.text = textThatFits 271 | sut.contentInset = customContentInset 272 | 273 | // Then 274 | 📸(sut) 275 | } 276 | 277 | func test_that_unfocused_button_with_truncated_text_and_custom_content_inset_renders_correctly() { 278 | // Given 279 | let customContentInset = UIEdgeInsets(top: 20, left: 35, bottom: 20, right: 35) 280 | 281 | // When 282 | sut.text = longText 283 | sut.contentInset = customContentInset 284 | 285 | // Then 286 | 📸(sut) 287 | } 288 | 289 | // MARK: - Private 290 | 291 | // swiftlint:disable identifier_name 292 | private func 📸(_ view: UIView, file: StaticString = #file, testName: String = #function, line: UInt = #line) { 293 | // swiftlint:enable identifier_name 294 | 295 | var frame = sut.bounds 296 | frame.size.width += 30 297 | frame.size.height += 30 298 | 299 | let containerView = UIView(frame: frame) 300 | containerView.backgroundColor = .darkGray 301 | containerView.addSubview(view) 302 | sut.center = containerView.center 303 | 304 | assertSnapshot( 305 | matching: containerView, 306 | as: .image, 307 | file: file, 308 | testName: testName, 309 | line: line 310 | ) 311 | } 312 | } 313 | 314 | extension Bundle { 315 | static func testBundle() -> Bundle! { 316 | return Bundle(for: Tests_TvOSMoreButton.self) 317 | } 318 | } 319 | 320 | let longText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt" 321 | let textThatFits = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor inc." 322 | -------------------------------------------------------------------------------- /Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_button_with_truncated_text_has_unfocused_appearance_after_being_focused.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_button_with_truncated_text_has_unfocused_appearance_after_being_focused.1.png -------------------------------------------------------------------------------- /Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_focused_button_with_truncated_text_renders_correctly.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_focused_button_with_truncated_text_renders_correctly.1.png -------------------------------------------------------------------------------- /Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_text_that_fits_and_custom_content_inset_renders_correctly.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_text_that_fits_and_custom_content_inset_renders_correctly.1.png -------------------------------------------------------------------------------- /Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_text_that_fits_and_custom_font_renders_correctly.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_text_that_fits_and_custom_font_renders_correctly.1.png -------------------------------------------------------------------------------- /Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_text_that_fits_and_custom_text_alignment_renders_correctly.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_text_that_fits_and_custom_text_alignment_renders_correctly.1.png -------------------------------------------------------------------------------- /Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_text_that_fits_and_custom_text_color_renders_correctly.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_text_that_fits_and_custom_text_color_renders_correctly.1.png -------------------------------------------------------------------------------- /Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_text_that_fits_renders_correctly.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_text_that_fits_renders_correctly.1.png -------------------------------------------------------------------------------- /Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_and_and_custom_text_color_renders_correctly.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_and_and_custom_text_color_renders_correctly.1.png -------------------------------------------------------------------------------- /Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_and_custom_content_inset_renders_correctly.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_and_custom_content_inset_renders_correctly.1.png -------------------------------------------------------------------------------- /Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_and_custom_ellipses_string_renders_correctly.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_and_custom_ellipses_string_renders_correctly.1.png -------------------------------------------------------------------------------- /Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_and_custom_font_renders_correctly.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_and_custom_font_renders_correctly.1.png -------------------------------------------------------------------------------- /Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_and_custom_text_alignment_renders_correctly.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_and_custom_text_alignment_renders_correctly.1.png -------------------------------------------------------------------------------- /Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_and_custom_trailing_text_color_renders_correctly.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_and_custom_trailing_text_color_renders_correctly.1.png -------------------------------------------------------------------------------- /Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_and_custom_trailing_text_font_renders_correctly.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_and_custom_trailing_text_font_renders_correctly.1.png -------------------------------------------------------------------------------- /Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_and_custom_trailing_text_renders_correctly.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_and_custom_trailing_text_renders_correctly.1.png -------------------------------------------------------------------------------- /Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_renders_correctly.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cgoldsby/TvOSMoreButton/5d658b2d4f4439e29b94d6979fb037751f3762f2/Tests/Public/Views/__Snapshots__/Tests_TvOSMoreButton/test_that_unfocused_button_with_truncated_text_renders_correctly.1.png -------------------------------------------------------------------------------- /Tests/Resources/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | TvOSMoreButton 4 | 5 | Created by Christopher Goldsby on 8/5/19. 6 | Copyright © 2019 Christopher Goldsby. All rights reserved. 7 | */ 8 | 9 | /* Text that appears after a long description in a label */ 10 | "TvOSMoreButton.More.Text" = "More"; 11 | -------------------------------------------------------------------------------- /TvOSMoreButton.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'TvOSMoreButton' 3 | s.authors = { 'Chris Goldsby' => 'cgoldsby@gmail.com' } 4 | s.version = '1.4.1' 5 | s.license = 'MIT' 6 | s.summary = 'tvOS \'... More\' Button' 7 | s.homepage = 'https://github.com/cgoldsby/TvOSMoreButton' 8 | s.source = { 9 | git: 'https://github.com/cgoldsby/TvOSMoreButton.git', 10 | tag: s.version 11 | } 12 | s.swift_version = '5.0' 13 | s.tvos.deployment_target = '9.0' 14 | s.source_files = 'Source/**/*.swift' 15 | s.resource_bundle = { 'TvOSMoreButton' => ['Resources/*.lproj'] } 16 | end 17 | -------------------------------------------------------------------------------- /TvOSMoreButton.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | EB52FF2C1DBCF6AA00F97D2B /* BundleLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB52FF2B1DBCF6AA00F97D2B /* BundleLoader.swift */; }; 11 | EB76C5B01DB5873B0014B8D5 /* TvOSMoreButton.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EB76C5A61DB5873B0014B8D5 /* TvOSMoreButton.framework */; }; 12 | EB88B1FE1E86F6EC00CBAB27 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = EB88B2001E86F6EC00CBAB27 /* Localizable.strings */; }; 13 | EB96ECF222F7565C00649C4E /* Tests_TvOSMoreButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB96ECF122F7565C00649C4E /* Tests_TvOSMoreButton.swift */; }; 14 | EBA6991E1DB938C700D1818C /* LocalizedStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBA699141DB938C700D1818C /* LocalizedStrings.swift */; }; 15 | EBA6991F1DB938C700D1818C /* String+Truncation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBA699151DB938C700D1818C /* String+Truncation.swift */; }; 16 | EBA699201DB938C700D1818C /* UIView+Autolayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBA699161DB938C700D1818C /* UIView+Autolayout.swift */; }; 17 | EBA699221DB938C700D1818C /* TvOSMoreButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBA6991B1DB938C700D1818C /* TvOSMoreButton.swift */; }; 18 | EBA699281DB93A5A00D1818C /* TvOSMoreButton.h in Headers */ = {isa = PBXBuildFile; fileRef = EBA699101DB938C700D1818C /* TvOSMoreButton.h */; settings = {ATTRIBUTES = (Public, ); }; }; 19 | EBDB171A22F8B2EB00152EC0 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = EBDB171922F8B2EB00152EC0 /* Localizable.strings */; }; 20 | F19B7E7CD6AA838829204C0B /* Pods_UnitTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DEB66589A984B3E76FC3824E /* Pods_UnitTests.framework */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | EB76C5B11DB5873B0014B8D5 /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = EB76C59D1DB5873B0014B8D5 /* Project object */; 27 | proxyType = 1; 28 | remoteGlobalIDString = EB76C5A51DB5873B0014B8D5; 29 | remoteInfo = ExpandingDescriptionView; 30 | }; 31 | /* End PBXContainerItemProxy section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | 14F158AF9761DA74D40E691F /* Pods-UnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.release.xcconfig"; sourceTree = ""; }; 35 | 1F445DA284EF7DBB66E34F2D /* Pods-UnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-UnitTests/Pods-UnitTests.debug.xcconfig"; sourceTree = ""; }; 36 | DEB66589A984B3E76FC3824E /* Pods_UnitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_UnitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | EB52FF2B1DBCF6AA00F97D2B /* BundleLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BundleLoader.swift; sourceTree = ""; }; 38 | EB76C5A61DB5873B0014B8D5 /* TvOSMoreButton.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TvOSMoreButton.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | EB76C5AF1DB5873B0014B8D5 /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | EB88B1FF1E86F6EC00CBAB27 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 41 | EB88B2011E86F70300CBAB27 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; 42 | EB88B2021E86F70800CBAB27 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; 43 | EB88B2031E86F71300CBAB27 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; }; 44 | EB88B2041E86F72100CBAB27 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; 45 | EB96ECF122F7565C00649C4E /* Tests_TvOSMoreButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests_TvOSMoreButton.swift; sourceTree = ""; }; 46 | EBA699101DB938C700D1818C /* TvOSMoreButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TvOSMoreButton.h; sourceTree = ""; }; 47 | EBA699111DB938C700D1818C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 48 | EBA699141DB938C700D1818C /* LocalizedStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizedStrings.swift; sourceTree = ""; }; 49 | EBA699151DB938C700D1818C /* String+Truncation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Truncation.swift"; sourceTree = ""; }; 50 | EBA699161DB938C700D1818C /* UIView+Autolayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Autolayout.swift"; sourceTree = ""; }; 51 | EBA6991B1DB938C700D1818C /* TvOSMoreButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TvOSMoreButton.swift; sourceTree = ""; }; 52 | EBA699251DB938D100D1818C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 53 | EBAD63A41EAD70E00007B48B /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; 54 | EBAD63A51EAD71B20007B48B /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Localizable.strings; sourceTree = ""; }; 55 | EBAD63A61EAD71E50007B48B /* es-MX */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-MX"; path = "es-MX.lproj/Localizable.strings"; sourceTree = ""; }; 56 | EBAD63A71EAD72210007B48B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; 57 | EBAD63A81EAD72B00007B48B /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; 58 | EBDB171922F8B2EB00152EC0 /* Localizable.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = ""; }; 59 | /* End PBXFileReference section */ 60 | 61 | /* Begin PBXFrameworksBuildPhase section */ 62 | EB76C5A21DB5873B0014B8D5 /* Frameworks */ = { 63 | isa = PBXFrameworksBuildPhase; 64 | buildActionMask = 2147483647; 65 | files = ( 66 | ); 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | EB76C5AC1DB5873B0014B8D5 /* Frameworks */ = { 70 | isa = PBXFrameworksBuildPhase; 71 | buildActionMask = 2147483647; 72 | files = ( 73 | EB76C5B01DB5873B0014B8D5 /* TvOSMoreButton.framework in Frameworks */, 74 | F19B7E7CD6AA838829204C0B /* Pods_UnitTests.framework in Frameworks */, 75 | ); 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | /* End PBXFrameworksBuildPhase section */ 79 | 80 | /* Begin PBXGroup section */ 81 | AEEA938F9C0EF5A490A8BE9B /* Pods */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 1F445DA284EF7DBB66E34F2D /* Pods-UnitTests.debug.xcconfig */, 85 | 14F158AF9761DA74D40E691F /* Pods-UnitTests.release.xcconfig */, 86 | ); 87 | name = Pods; 88 | sourceTree = ""; 89 | }; 90 | EB76C59C1DB5873B0014B8D5 = { 91 | isa = PBXGroup; 92 | children = ( 93 | EBA6990F1DB938C700D1818C /* Source */, 94 | EBA699231DB938D100D1818C /* Tests */, 95 | EBA6990E1DB938C700D1818C /* Resources */, 96 | EB76C5A71DB5873B0014B8D5 /* Products */, 97 | AEEA938F9C0EF5A490A8BE9B /* Pods */, 98 | F3544326E084FA17418DBC58 /* Frameworks */, 99 | ); 100 | sourceTree = ""; 101 | }; 102 | EB76C5A71DB5873B0014B8D5 /* Products */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | EB76C5A61DB5873B0014B8D5 /* TvOSMoreButton.framework */, 106 | EB76C5AF1DB5873B0014B8D5 /* UnitTests.xctest */, 107 | ); 108 | name = Products; 109 | sourceTree = ""; 110 | }; 111 | EB96ECEF22F755ED00649C4E /* Public */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | EB96ECF022F755F500649C4E /* Views */, 115 | ); 116 | path = Public; 117 | sourceTree = ""; 118 | }; 119 | EB96ECF022F755F500649C4E /* Views */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | EB96ECF122F7565C00649C4E /* Tests_TvOSMoreButton.swift */, 123 | ); 124 | path = Views; 125 | sourceTree = ""; 126 | }; 127 | EBA6990E1DB938C700D1818C /* Resources */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | EB88B2001E86F6EC00CBAB27 /* Localizable.strings */, 131 | ); 132 | path = Resources; 133 | sourceTree = ""; 134 | }; 135 | EBA6990F1DB938C700D1818C /* Source */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | EBA699191DB938C700D1818C /* Public */, 139 | EBA699121DB938C700D1818C /* Private */, 140 | EBA699101DB938C700D1818C /* TvOSMoreButton.h */, 141 | EBA699111DB938C700D1818C /* Info.plist */, 142 | ); 143 | path = Source; 144 | sourceTree = ""; 145 | }; 146 | EBA699121DB938C700D1818C /* Private */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | EBA699131DB938C700D1818C /* Helpers */, 150 | ); 151 | path = Private; 152 | sourceTree = ""; 153 | }; 154 | EBA699131DB938C700D1818C /* Helpers */ = { 155 | isa = PBXGroup; 156 | children = ( 157 | EB52FF2B1DBCF6AA00F97D2B /* BundleLoader.swift */, 158 | EBA699141DB938C700D1818C /* LocalizedStrings.swift */, 159 | EBA699151DB938C700D1818C /* String+Truncation.swift */, 160 | EBA699161DB938C700D1818C /* UIView+Autolayout.swift */, 161 | ); 162 | path = Helpers; 163 | sourceTree = ""; 164 | }; 165 | EBA699191DB938C700D1818C /* Public */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | EBA6991A1DB938C700D1818C /* Views */, 169 | ); 170 | path = Public; 171 | sourceTree = ""; 172 | }; 173 | EBA6991A1DB938C700D1818C /* Views */ = { 174 | isa = PBXGroup; 175 | children = ( 176 | EBA6991B1DB938C700D1818C /* TvOSMoreButton.swift */, 177 | ); 178 | path = Views; 179 | sourceTree = ""; 180 | }; 181 | EBA699231DB938D100D1818C /* Tests */ = { 182 | isa = PBXGroup; 183 | children = ( 184 | EB96ECEF22F755ED00649C4E /* Public */, 185 | EBDB171822F8B2BD00152EC0 /* Resources */, 186 | EBA699251DB938D100D1818C /* Info.plist */, 187 | ); 188 | path = Tests; 189 | sourceTree = ""; 190 | }; 191 | EBDB171822F8B2BD00152EC0 /* Resources */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | EBDB171922F8B2EB00152EC0 /* Localizable.strings */, 195 | ); 196 | path = Resources; 197 | sourceTree = ""; 198 | }; 199 | F3544326E084FA17418DBC58 /* Frameworks */ = { 200 | isa = PBXGroup; 201 | children = ( 202 | DEB66589A984B3E76FC3824E /* Pods_UnitTests.framework */, 203 | ); 204 | name = Frameworks; 205 | sourceTree = ""; 206 | }; 207 | /* End PBXGroup section */ 208 | 209 | /* Begin PBXHeadersBuildPhase section */ 210 | EB76C5A31DB5873B0014B8D5 /* Headers */ = { 211 | isa = PBXHeadersBuildPhase; 212 | buildActionMask = 2147483647; 213 | files = ( 214 | EBA699281DB93A5A00D1818C /* TvOSMoreButton.h in Headers */, 215 | ); 216 | runOnlyForDeploymentPostprocessing = 0; 217 | }; 218 | /* End PBXHeadersBuildPhase section */ 219 | 220 | /* Begin PBXNativeTarget section */ 221 | EB76C5A51DB5873B0014B8D5 /* TvOSMoreButton */ = { 222 | isa = PBXNativeTarget; 223 | buildConfigurationList = EB76C5BA1DB5873B0014B8D5 /* Build configuration list for PBXNativeTarget "TvOSMoreButton" */; 224 | buildPhases = ( 225 | EBEACC9C1E7158690075CBD3 /* [TvOSMoreButton] Linter */, 226 | EB76C5A11DB5873B0014B8D5 /* Sources */, 227 | EB76C5A21DB5873B0014B8D5 /* Frameworks */, 228 | EB76C5A31DB5873B0014B8D5 /* Headers */, 229 | EB76C5A41DB5873B0014B8D5 /* Resources */, 230 | ); 231 | buildRules = ( 232 | ); 233 | dependencies = ( 234 | ); 235 | name = TvOSMoreButton; 236 | productName = ExpandingDescriptionView; 237 | productReference = EB76C5A61DB5873B0014B8D5 /* TvOSMoreButton.framework */; 238 | productType = "com.apple.product-type.framework"; 239 | }; 240 | EB76C5AE1DB5873B0014B8D5 /* UnitTests */ = { 241 | isa = PBXNativeTarget; 242 | buildConfigurationList = EB76C5BD1DB5873B0014B8D5 /* Build configuration list for PBXNativeTarget "UnitTests" */; 243 | buildPhases = ( 244 | B62F20E9E46D13E0D892233B /* [CP] Check Pods Manifest.lock */, 245 | EBEACC9D1E7158A20075CBD3 /* [TvOSMoreButton] Linter */, 246 | EB76C5AB1DB5873B0014B8D5 /* Sources */, 247 | EB76C5AC1DB5873B0014B8D5 /* Frameworks */, 248 | EB76C5AD1DB5873B0014B8D5 /* Resources */, 249 | A46CF1E8F5B335BA3BBCDC2B /* [CP] Embed Pods Frameworks */, 250 | ); 251 | buildRules = ( 252 | ); 253 | dependencies = ( 254 | EB76C5B21DB5873B0014B8D5 /* PBXTargetDependency */, 255 | ); 256 | name = UnitTests; 257 | productName = ExpandingDescriptionViewTests; 258 | productReference = EB76C5AF1DB5873B0014B8D5 /* UnitTests.xctest */; 259 | productType = "com.apple.product-type.bundle.unit-test"; 260 | }; 261 | /* End PBXNativeTarget section */ 262 | 263 | /* Begin PBXProject section */ 264 | EB76C59D1DB5873B0014B8D5 /* Project object */ = { 265 | isa = PBXProject; 266 | attributes = { 267 | LastSwiftUpdateCheck = 0800; 268 | LastUpgradeCheck = 1320; 269 | ORGANIZATIONNAME = "Christopher Goldsby"; 270 | TargetAttributes = { 271 | EB76C5A51DB5873B0014B8D5 = { 272 | CreatedOnToolsVersion = 8.0; 273 | LastSwiftMigration = 1030; 274 | ProvisioningStyle = Manual; 275 | }; 276 | EB76C5AE1DB5873B0014B8D5 = { 277 | CreatedOnToolsVersion = 8.0; 278 | LastSwiftMigration = 1030; 279 | ProvisioningStyle = Manual; 280 | }; 281 | }; 282 | }; 283 | buildConfigurationList = EB76C5A01DB5873B0014B8D5 /* Build configuration list for PBXProject "TvOSMoreButton" */; 284 | compatibilityVersion = "Xcode 3.2"; 285 | developmentRegion = en; 286 | hasScannedForEncodings = 0; 287 | knownRegions = ( 288 | en, 289 | fr, 290 | de, 291 | it, 292 | es, 293 | ja, 294 | nb, 295 | "es-MX", 296 | ru, 297 | nl, 298 | Base, 299 | ); 300 | mainGroup = EB76C59C1DB5873B0014B8D5; 301 | productRefGroup = EB76C5A71DB5873B0014B8D5 /* Products */; 302 | projectDirPath = ""; 303 | projectRoot = ""; 304 | targets = ( 305 | EB76C5A51DB5873B0014B8D5 /* TvOSMoreButton */, 306 | EB76C5AE1DB5873B0014B8D5 /* UnitTests */, 307 | ); 308 | }; 309 | /* End PBXProject section */ 310 | 311 | /* Begin PBXResourcesBuildPhase section */ 312 | EB76C5A41DB5873B0014B8D5 /* Resources */ = { 313 | isa = PBXResourcesBuildPhase; 314 | buildActionMask = 2147483647; 315 | files = ( 316 | EB88B1FE1E86F6EC00CBAB27 /* Localizable.strings in Resources */, 317 | ); 318 | runOnlyForDeploymentPostprocessing = 0; 319 | }; 320 | EB76C5AD1DB5873B0014B8D5 /* Resources */ = { 321 | isa = PBXResourcesBuildPhase; 322 | buildActionMask = 2147483647; 323 | files = ( 324 | EBDB171A22F8B2EB00152EC0 /* Localizable.strings in Resources */, 325 | ); 326 | runOnlyForDeploymentPostprocessing = 0; 327 | }; 328 | /* End PBXResourcesBuildPhase section */ 329 | 330 | /* Begin PBXShellScriptBuildPhase section */ 331 | A46CF1E8F5B335BA3BBCDC2B /* [CP] Embed Pods Frameworks */ = { 332 | isa = PBXShellScriptBuildPhase; 333 | buildActionMask = 2147483647; 334 | files = ( 335 | ); 336 | inputPaths = ( 337 | "${PODS_ROOT}/Target Support Files/Pods-UnitTests/Pods-UnitTests-frameworks.sh", 338 | "${BUILT_PRODUCTS_DIR}/SnapshotTesting/SnapshotTesting.framework", 339 | ); 340 | name = "[CP] Embed Pods Frameworks"; 341 | outputPaths = ( 342 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapshotTesting.framework", 343 | ); 344 | runOnlyForDeploymentPostprocessing = 0; 345 | shellPath = /bin/sh; 346 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-UnitTests/Pods-UnitTests-frameworks.sh\"\n"; 347 | showEnvVarsInLog = 0; 348 | }; 349 | B62F20E9E46D13E0D892233B /* [CP] Check Pods Manifest.lock */ = { 350 | isa = PBXShellScriptBuildPhase; 351 | buildActionMask = 2147483647; 352 | files = ( 353 | ); 354 | inputFileListPaths = ( 355 | ); 356 | inputPaths = ( 357 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 358 | "${PODS_ROOT}/Manifest.lock", 359 | ); 360 | name = "[CP] Check Pods Manifest.lock"; 361 | outputFileListPaths = ( 362 | ); 363 | outputPaths = ( 364 | "$(DERIVED_FILE_DIR)/Pods-UnitTests-checkManifestLockResult.txt", 365 | ); 366 | runOnlyForDeploymentPostprocessing = 0; 367 | shellPath = /bin/sh; 368 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 369 | showEnvVarsInLog = 0; 370 | }; 371 | EBEACC9C1E7158690075CBD3 /* [TvOSMoreButton] Linter */ = { 372 | isa = PBXShellScriptBuildPhase; 373 | buildActionMask = 2147483647; 374 | files = ( 375 | ); 376 | inputPaths = ( 377 | ); 378 | name = "[TvOSMoreButton] Linter"; 379 | outputPaths = ( 380 | ); 381 | runOnlyForDeploymentPostprocessing = 0; 382 | shellPath = /bin/sh; 383 | shellScript = "Pods/SwiftLint/swiftlint\n"; 384 | }; 385 | EBEACC9D1E7158A20075CBD3 /* [TvOSMoreButton] Linter */ = { 386 | isa = PBXShellScriptBuildPhase; 387 | buildActionMask = 2147483647; 388 | files = ( 389 | ); 390 | inputPaths = ( 391 | ); 392 | name = "[TvOSMoreButton] Linter"; 393 | outputPaths = ( 394 | ); 395 | runOnlyForDeploymentPostprocessing = 0; 396 | shellPath = /bin/sh; 397 | shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; 398 | }; 399 | /* End PBXShellScriptBuildPhase section */ 400 | 401 | /* Begin PBXSourcesBuildPhase section */ 402 | EB76C5A11DB5873B0014B8D5 /* Sources */ = { 403 | isa = PBXSourcesBuildPhase; 404 | buildActionMask = 2147483647; 405 | files = ( 406 | EB52FF2C1DBCF6AA00F97D2B /* BundleLoader.swift in Sources */, 407 | EBA6991E1DB938C700D1818C /* LocalizedStrings.swift in Sources */, 408 | EBA699221DB938C700D1818C /* TvOSMoreButton.swift in Sources */, 409 | EBA699201DB938C700D1818C /* UIView+Autolayout.swift in Sources */, 410 | EBA6991F1DB938C700D1818C /* String+Truncation.swift in Sources */, 411 | ); 412 | runOnlyForDeploymentPostprocessing = 0; 413 | }; 414 | EB76C5AB1DB5873B0014B8D5 /* Sources */ = { 415 | isa = PBXSourcesBuildPhase; 416 | buildActionMask = 2147483647; 417 | files = ( 418 | EB96ECF222F7565C00649C4E /* Tests_TvOSMoreButton.swift in Sources */, 419 | ); 420 | runOnlyForDeploymentPostprocessing = 0; 421 | }; 422 | /* End PBXSourcesBuildPhase section */ 423 | 424 | /* Begin PBXTargetDependency section */ 425 | EB76C5B21DB5873B0014B8D5 /* PBXTargetDependency */ = { 426 | isa = PBXTargetDependency; 427 | target = EB76C5A51DB5873B0014B8D5 /* TvOSMoreButton */; 428 | targetProxy = EB76C5B11DB5873B0014B8D5 /* PBXContainerItemProxy */; 429 | }; 430 | /* End PBXTargetDependency section */ 431 | 432 | /* Begin PBXVariantGroup section */ 433 | EB88B2001E86F6EC00CBAB27 /* Localizable.strings */ = { 434 | isa = PBXVariantGroup; 435 | children = ( 436 | EB88B1FF1E86F6EC00CBAB27 /* en */, 437 | EB88B2011E86F70300CBAB27 /* fr */, 438 | EB88B2021E86F70800CBAB27 /* de */, 439 | EB88B2031E86F71300CBAB27 /* it */, 440 | EB88B2041E86F72100CBAB27 /* es */, 441 | EBAD63A41EAD70E00007B48B /* ja */, 442 | EBAD63A51EAD71B20007B48B /* nb */, 443 | EBAD63A61EAD71E50007B48B /* es-MX */, 444 | EBAD63A71EAD72210007B48B /* ru */, 445 | EBAD63A81EAD72B00007B48B /* nl */, 446 | ); 447 | name = Localizable.strings; 448 | sourceTree = ""; 449 | }; 450 | /* End PBXVariantGroup section */ 451 | 452 | /* Begin XCBuildConfiguration section */ 453 | EB76C5B81DB5873B0014B8D5 /* Debug */ = { 454 | isa = XCBuildConfiguration; 455 | buildSettings = { 456 | ALWAYS_SEARCH_USER_PATHS = NO; 457 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 458 | CLANG_ANALYZER_NONNULL = YES; 459 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 460 | CLANG_CXX_LIBRARY = "libc++"; 461 | CLANG_ENABLE_MODULES = YES; 462 | CLANG_ENABLE_OBJC_ARC = YES; 463 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 464 | CLANG_WARN_BOOL_CONVERSION = YES; 465 | CLANG_WARN_COMMA = YES; 466 | CLANG_WARN_CONSTANT_CONVERSION = YES; 467 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 468 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 469 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 470 | CLANG_WARN_EMPTY_BODY = YES; 471 | CLANG_WARN_ENUM_CONVERSION = YES; 472 | CLANG_WARN_INFINITE_RECURSION = YES; 473 | CLANG_WARN_INT_CONVERSION = YES; 474 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 475 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 476 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 477 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 478 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 479 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 480 | CLANG_WARN_STRICT_PROTOTYPES = YES; 481 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 482 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 483 | CLANG_WARN_UNREACHABLE_CODE = YES; 484 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 485 | COPY_PHASE_STRIP = NO; 486 | CURRENT_PROJECT_VERSION = 1; 487 | DEBUG_INFORMATION_FORMAT = dwarf; 488 | ENABLE_STRICT_OBJC_MSGSEND = YES; 489 | ENABLE_TESTABILITY = YES; 490 | GCC_C_LANGUAGE_STANDARD = gnu99; 491 | GCC_DYNAMIC_NO_PIC = NO; 492 | GCC_NO_COMMON_BLOCKS = YES; 493 | GCC_OPTIMIZATION_LEVEL = 0; 494 | GCC_PREPROCESSOR_DEFINITIONS = ( 495 | "DEBUG=1", 496 | "$(inherited)", 497 | ); 498 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 499 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 500 | GCC_WARN_UNDECLARED_SELECTOR = YES; 501 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 502 | GCC_WARN_UNUSED_FUNCTION = YES; 503 | GCC_WARN_UNUSED_VARIABLE = YES; 504 | MTL_ENABLE_DEBUG_INFO = YES; 505 | ONLY_ACTIVE_ARCH = YES; 506 | SDKROOT = appletvos; 507 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 508 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 509 | SWIFT_VERSION = 5.0; 510 | TARGETED_DEVICE_FAMILY = 3; 511 | TVOS_DEPLOYMENT_TARGET = 10.0; 512 | VERSIONING_SYSTEM = "apple-generic"; 513 | VERSION_INFO_PREFIX = ""; 514 | }; 515 | name = Debug; 516 | }; 517 | EB76C5B91DB5873B0014B8D5 /* Release */ = { 518 | isa = XCBuildConfiguration; 519 | buildSettings = { 520 | ALWAYS_SEARCH_USER_PATHS = NO; 521 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 522 | CLANG_ANALYZER_NONNULL = YES; 523 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 524 | CLANG_CXX_LIBRARY = "libc++"; 525 | CLANG_ENABLE_MODULES = YES; 526 | CLANG_ENABLE_OBJC_ARC = YES; 527 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 528 | CLANG_WARN_BOOL_CONVERSION = YES; 529 | CLANG_WARN_COMMA = YES; 530 | CLANG_WARN_CONSTANT_CONVERSION = YES; 531 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 532 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 533 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 534 | CLANG_WARN_EMPTY_BODY = YES; 535 | CLANG_WARN_ENUM_CONVERSION = YES; 536 | CLANG_WARN_INFINITE_RECURSION = YES; 537 | CLANG_WARN_INT_CONVERSION = YES; 538 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 539 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 540 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 541 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 542 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 543 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 544 | CLANG_WARN_STRICT_PROTOTYPES = YES; 545 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 546 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 547 | CLANG_WARN_UNREACHABLE_CODE = YES; 548 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 549 | COPY_PHASE_STRIP = NO; 550 | CURRENT_PROJECT_VERSION = 1; 551 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 552 | ENABLE_NS_ASSERTIONS = NO; 553 | ENABLE_STRICT_OBJC_MSGSEND = YES; 554 | GCC_C_LANGUAGE_STANDARD = gnu99; 555 | GCC_NO_COMMON_BLOCKS = YES; 556 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 557 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 558 | GCC_WARN_UNDECLARED_SELECTOR = YES; 559 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 560 | GCC_WARN_UNUSED_FUNCTION = YES; 561 | GCC_WARN_UNUSED_VARIABLE = YES; 562 | MTL_ENABLE_DEBUG_INFO = NO; 563 | SDKROOT = appletvos; 564 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 565 | SWIFT_VERSION = 5.0; 566 | TARGETED_DEVICE_FAMILY = 3; 567 | TVOS_DEPLOYMENT_TARGET = 10.0; 568 | VALIDATE_PRODUCT = YES; 569 | VERSIONING_SYSTEM = "apple-generic"; 570 | VERSION_INFO_PREFIX = ""; 571 | }; 572 | name = Release; 573 | }; 574 | EB76C5BB1DB5873B0014B8D5 /* Debug */ = { 575 | isa = XCBuildConfiguration; 576 | buildSettings = { 577 | CLANG_ENABLE_MODULES = YES; 578 | CODE_SIGN_IDENTITY = ""; 579 | DEFINES_MODULE = YES; 580 | DEVELOPMENT_TEAM = ""; 581 | DYLIB_COMPATIBILITY_VERSION = 1; 582 | DYLIB_CURRENT_VERSION = 1; 583 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 584 | INFOPLIST_FILE = Source/Info.plist; 585 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 586 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 587 | PRODUCT_BUNDLE_IDENTIFIER = com.cgoldsby.TvOSMoreButton; 588 | PRODUCT_NAME = "$(TARGET_NAME)"; 589 | SKIP_INSTALL = YES; 590 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 591 | SWIFT_VERSION = 5.0; 592 | }; 593 | name = Debug; 594 | }; 595 | EB76C5BC1DB5873B0014B8D5 /* Release */ = { 596 | isa = XCBuildConfiguration; 597 | buildSettings = { 598 | CLANG_ENABLE_MODULES = YES; 599 | CODE_SIGN_IDENTITY = ""; 600 | DEFINES_MODULE = YES; 601 | DEVELOPMENT_TEAM = ""; 602 | DYLIB_COMPATIBILITY_VERSION = 1; 603 | DYLIB_CURRENT_VERSION = 1; 604 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 605 | INFOPLIST_FILE = Source/Info.plist; 606 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 607 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 608 | PRODUCT_BUNDLE_IDENTIFIER = com.cgoldsby.TvOSMoreButton; 609 | PRODUCT_NAME = "$(TARGET_NAME)"; 610 | SKIP_INSTALL = YES; 611 | SWIFT_VERSION = 5.0; 612 | }; 613 | name = Release; 614 | }; 615 | EB76C5BE1DB5873B0014B8D5 /* Debug */ = { 616 | isa = XCBuildConfiguration; 617 | baseConfigurationReference = 1F445DA284EF7DBB66E34F2D /* Pods-UnitTests.debug.xcconfig */; 618 | buildSettings = { 619 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 620 | CLANG_ENABLE_MODULES = YES; 621 | CODE_SIGN_IDENTITY = ""; 622 | INFOPLIST_FILE = Tests/Info.plist; 623 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 624 | PRODUCT_BUNDLE_IDENTIFIER = com.cgoldsby.TvOSMoreButton.UnitTests; 625 | PRODUCT_NAME = "$(TARGET_NAME)"; 626 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 627 | SWIFT_VERSION = 5.0; 628 | }; 629 | name = Debug; 630 | }; 631 | EB76C5BF1DB5873B0014B8D5 /* Release */ = { 632 | isa = XCBuildConfiguration; 633 | baseConfigurationReference = 14F158AF9761DA74D40E691F /* Pods-UnitTests.release.xcconfig */; 634 | buildSettings = { 635 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 636 | CLANG_ENABLE_MODULES = YES; 637 | CODE_SIGN_IDENTITY = ""; 638 | INFOPLIST_FILE = Tests/Info.plist; 639 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 640 | PRODUCT_BUNDLE_IDENTIFIER = com.cgoldsby.TvOSMoreButton.UnitTests; 641 | PRODUCT_NAME = "$(TARGET_NAME)"; 642 | SWIFT_VERSION = 5.0; 643 | }; 644 | name = Release; 645 | }; 646 | /* End XCBuildConfiguration section */ 647 | 648 | /* Begin XCConfigurationList section */ 649 | EB76C5A01DB5873B0014B8D5 /* Build configuration list for PBXProject "TvOSMoreButton" */ = { 650 | isa = XCConfigurationList; 651 | buildConfigurations = ( 652 | EB76C5B81DB5873B0014B8D5 /* Debug */, 653 | EB76C5B91DB5873B0014B8D5 /* Release */, 654 | ); 655 | defaultConfigurationIsVisible = 0; 656 | defaultConfigurationName = Release; 657 | }; 658 | EB76C5BA1DB5873B0014B8D5 /* Build configuration list for PBXNativeTarget "TvOSMoreButton" */ = { 659 | isa = XCConfigurationList; 660 | buildConfigurations = ( 661 | EB76C5BB1DB5873B0014B8D5 /* Debug */, 662 | EB76C5BC1DB5873B0014B8D5 /* Release */, 663 | ); 664 | defaultConfigurationIsVisible = 0; 665 | defaultConfigurationName = Release; 666 | }; 667 | EB76C5BD1DB5873B0014B8D5 /* Build configuration list for PBXNativeTarget "UnitTests" */ = { 668 | isa = XCConfigurationList; 669 | buildConfigurations = ( 670 | EB76C5BE1DB5873B0014B8D5 /* Debug */, 671 | EB76C5BF1DB5873B0014B8D5 /* Release */, 672 | ); 673 | defaultConfigurationIsVisible = 0; 674 | defaultConfigurationName = Release; 675 | }; 676 | /* End XCConfigurationList section */ 677 | }; 678 | rootObject = EB76C59D1DB5873B0014B8D5 /* Project object */; 679 | } 680 | -------------------------------------------------------------------------------- /TvOSMoreButton.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TvOSMoreButton.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /TvOSMoreButton.xcodeproj/xcshareddata/xcschemes/TvOSMoreButton.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 38 | 39 | 40 | 41 | 44 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 80 | 81 | 87 | 88 | 89 | 90 | 92 | 93 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /TvOSMoreButton.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /TvOSMoreButton.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /TvOSMoreButton.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | 8 | 9 | --------------------------------------------------------------------------------