├── .gitignore ├── .readme ├── logo.png └── tinderbar.gif ├── LICENSE ├── README.md ├── Sources ├── Tinderbar.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── Tinderbar │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── app_icon-1.png │ │ ├── app_icon-2.png │ │ └── app_icon.png │ ├── Contents.json │ ├── ic_launch_logo.imageset │ │ ├── Contents.json │ │ ├── ic_launch_logo.png │ │ ├── ic_launch_logo@2x.png │ │ └── ic_launch_logo@3x.png │ ├── ic_matches.imageset │ │ ├── Contents.json │ │ └── ic_tinder.pdf │ ├── ic_messages.imageset │ │ ├── Contents.json │ │ └── ic_messages.pdf │ └── ic_profile.imageset │ │ ├── Contents.json │ │ └── ic_profile.pdf │ ├── Bars │ ├── MessagesBar │ │ └── MessagesBar.swift │ └── TinderBar │ │ ├── TinderBar.swift │ │ ├── TinderBarButton.swift │ │ ├── TinderBarButtonContainer.swift │ │ └── TinderBarLayout.swift │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Root.storyboard │ ├── Info.plist │ ├── RootTabViewController.swift │ ├── TinderColors.swift │ ├── Utilities │ └── UIColor+Interpolation.swift │ └── ViewControllers │ ├── Matches │ ├── Matches.storyboard │ └── MatchesViewController.swift │ ├── Messages │ ├── Messages.storyboard │ ├── MessagesFeedViewController.swift │ ├── MessagesTabViewController.swift │ ├── MessagesViewController.swift │ └── Views │ │ ├── MessagesFeedCell.swift │ │ ├── MessagesFeedCell.xib │ │ ├── MessagesMessageCell.swift │ │ └── MessagesMessageCell.xib │ └── Profile │ ├── Profile.storyboard │ └── ProfileViewController.swift ├── Tinderbar.sketch └── Tinderbar.xcworkspace ├── contents.xcworkspacedata └── xcshareddata ├── IDEWorkspaceChecks.plist └── swiftpm └── Package.resolved /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | #build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | # Package.resolved 41 | .build/ 42 | 43 | # CocoaPods 44 | # 45 | # We recommend against adding the Pods directory to your .gitignore. However 46 | # you should judge for yourself, the pros and cons are mentioned at: 47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 48 | # 49 | # Pods/ 50 | 51 | # Carthage 52 | # 53 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 54 | # Carthage/Checkouts 55 | # Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots/**/*.png 67 | fastlane/test_output 68 | -------------------------------------------------------------------------------- /.readme/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uias/Tinderbar/a10dc9e8a7f456846bd882978ccefb232ffd6959/.readme/logo.png -------------------------------------------------------------------------------- /.readme/tinderbar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uias/Tinderbar/a10dc9e8a7f456846bd882978ccefb232ffd6959/.readme/tinderbar.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 UI At Six 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Tinderbar 3 | Tinderbar 4 |

5 | 6 | ## 🤔 About 7 | Tinderbar is a recreation of the Tinder iOS app's navigation hierarchy using [Tabman](https://github.com/uias/Tabman), a showcase of creating custom Tabman components. 8 | 9 | ### Requirements 10 | Latest version of Xcode. 11 | 12 | ## 🚀 Components 13 | Tinderbar uses Tabman for its primary navigation bar and also sub navigation within the Messages section. 14 | 15 | ### 🔥 TinderBar 16 | A `TMBarView` embedded in a `TMSystemBar`, added to the `.top`. 17 | ```swift 18 | TMBarView 19 | ``` 20 | 21 | It uses a custom layout in the form of [`TinderBarLayout`](./Sources/Tinderbar/Bars/TinderBar/TinderBarLayout.swift) and custom [`TinderBarButton`](./Sources/Tinderbar/Bars/TinderBar/TinderBarButton.swift) bar buttons. 22 | 23 | #### TinderBarLayout 24 | - Uses a horizontal stack view for buttons. 25 | - Buttons are inserted into a container, which is constrained to be `0.5x` the width of the `layoutGuide`. 26 | - Padding views of `0.25x` the `layoutGuide` are inserted at the leading and trailing edges of the stack. 27 | - Buttons are centered along the X-axis of their container, with a constant that is updated as the layout `focusArea` is adjusted (they are centered when selected, and offsetted when unselected to ensure they don't venture off screen). 28 | 29 | #### TinderBarButton 30 | - A `TMBarButton` which consists of an image view. 31 | - Image view tint color transitions between `unselectedTintColor` and `tintColor`. 32 | - Image view scales to `1.0` when selected and `0.8` when unselected. 33 | 34 | ### MessageBar 35 | A more regular `TMBarView` using stock Tabman components, added to the `.top`. 36 | ```swift 37 | TMBarView 38 | ``` 39 | - `contentMode` of the layout is set to `.fit`. 40 | 41 | ## 👨🏻‍💻 About 42 | - Created by [Merrick Sapsford](https://github.com/msaps) ([@MerrickSapsford](https://twitter.com/MerrickSapsford)). 43 | 44 | ## 👮🏻‍♂️ License 45 | The library is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). 46 | -------------------------------------------------------------------------------- /Sources/Tinderbar.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 53; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4612CD4D217E439400C1B4F7 /* RootTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4612CD4C217E439400C1B4F7 /* RootTabViewController.swift */; }; 11 | 4612CD51217E5BF500C1B4F7 /* TinderBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4612CD50217E5BF500C1B4F7 /* TinderBar.swift */; }; 12 | 4612CD53217E5C0400C1B4F7 /* TinderBarLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4612CD52217E5C0400C1B4F7 /* TinderBarLayout.swift */; }; 13 | 4612CD632180E70B00C1B4F7 /* TinderBarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4612CD622180E70B00C1B4F7 /* TinderBarButton.swift */; }; 14 | 4612CD652180EB7800C1B4F7 /* TinderBarButtonContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4612CD642180EB7800C1B4F7 /* TinderBarButtonContainer.swift */; }; 15 | 4612CD672180FFE900C1B4F7 /* TinderColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4612CD662180FFE900C1B4F7 /* TinderColors.swift */; }; 16 | 4612CD6A218101EC00C1B4F7 /* UIColor+Interpolation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4612CD69218101EC00C1B4F7 /* UIColor+Interpolation.swift */; }; 17 | 4612CD6C2181058900C1B4F7 /* MessagesTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4612CD6B2181058900C1B4F7 /* MessagesTabViewController.swift */; }; 18 | 4612CD6E218105AC00C1B4F7 /* MessagesFeedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4612CD6D218105AC00C1B4F7 /* MessagesFeedViewController.swift */; }; 19 | 4612CD70218106CF00C1B4F7 /* MessagesBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4612CD6F218106CF00C1B4F7 /* MessagesBar.swift */; }; 20 | 464264EF217E3FCD0001C4AF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 464264EE217E3FCD0001C4AF /* AppDelegate.swift */; }; 21 | 464264F4217E3FCD0001C4AF /* Root.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 464264F2217E3FCD0001C4AF /* Root.storyboard */; }; 22 | 464264F6217E3FCF0001C4AF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 464264F5217E3FCF0001C4AF /* Assets.xcassets */; }; 23 | 464264F9217E3FCF0001C4AF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 464264F7217E3FCF0001C4AF /* LaunchScreen.storyboard */; }; 24 | 46426509217E41E10001C4AF /* MessagesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46426508217E41E10001C4AF /* MessagesViewController.swift */; }; 25 | 4642650E217E42270001C4AF /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4642650D217E42270001C4AF /* ProfileViewController.swift */; }; 26 | 46426510217E42A60001C4AF /* Profile.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4642650F217E42A60001C4AF /* Profile.storyboard */; }; 27 | 46426512217E42BA0001C4AF /* Messages.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 46426511217E42BA0001C4AF /* Messages.storyboard */; }; 28 | 46426515217E42F20001C4AF /* MatchesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46426514217E42F20001C4AF /* MatchesViewController.swift */; }; 29 | 46426517217E43040001C4AF /* Matches.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 46426516217E43040001C4AF /* Matches.storyboard */; }; 30 | 46D36A4D218614CC0013635D /* MessagesMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D36A4C218614CC0013635D /* MessagesMessageCell.swift */; }; 31 | 46D36A4F218614D40013635D /* MessagesMessageCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 46D36A4E218614D40013635D /* MessagesMessageCell.xib */; }; 32 | 46D36A51218617ED0013635D /* MessagesFeedCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D36A50218617ED0013635D /* MessagesFeedCell.swift */; }; 33 | 46D36A53218617F60013635D /* MessagesFeedCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 46D36A52218617F60013635D /* MessagesFeedCell.xib */; }; 34 | 46F12DF823292C3B000EC76A /* Tabman in Frameworks */ = {isa = PBXBuildFile; productRef = 46F12DF723292C3B000EC76A /* Tabman */; }; 35 | /* End PBXBuildFile section */ 36 | 37 | /* Begin PBXFileReference section */ 38 | 4612CD4C217E439400C1B4F7 /* RootTabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootTabViewController.swift; sourceTree = ""; }; 39 | 4612CD50217E5BF500C1B4F7 /* TinderBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TinderBar.swift; sourceTree = ""; }; 40 | 4612CD52217E5C0400C1B4F7 /* TinderBarLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TinderBarLayout.swift; sourceTree = ""; }; 41 | 4612CD622180E70B00C1B4F7 /* TinderBarButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TinderBarButton.swift; sourceTree = ""; }; 42 | 4612CD642180EB7800C1B4F7 /* TinderBarButtonContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TinderBarButtonContainer.swift; sourceTree = ""; }; 43 | 4612CD662180FFE900C1B4F7 /* TinderColors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TinderColors.swift; sourceTree = ""; }; 44 | 4612CD69218101EC00C1B4F7 /* UIColor+Interpolation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Interpolation.swift"; sourceTree = ""; }; 45 | 4612CD6B2181058900C1B4F7 /* MessagesTabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesTabViewController.swift; sourceTree = ""; }; 46 | 4612CD6D218105AC00C1B4F7 /* MessagesFeedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesFeedViewController.swift; sourceTree = ""; }; 47 | 4612CD6F218106CF00C1B4F7 /* MessagesBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesBar.swift; sourceTree = ""; }; 48 | 464264EB217E3FCD0001C4AF /* Tinderbar.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Tinderbar.app; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 464264EE217E3FCD0001C4AF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 50 | 464264F3217E3FCD0001C4AF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Root.storyboard; sourceTree = ""; }; 51 | 464264F5217E3FCF0001C4AF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 52 | 464264F8217E3FCF0001C4AF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 53 | 464264FA217E3FCF0001C4AF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 54 | 46426501217E40B00001C4AF /* Pageboy.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Pageboy.framework; path = ../Carthage/Build/iOS/Pageboy.framework; sourceTree = ""; }; 55 | 46426502217E40B00001C4AF /* AutoInsetter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AutoInsetter.framework; path = ../Carthage/Build/iOS/AutoInsetter.framework; sourceTree = ""; }; 56 | 46426503217E40B00001C4AF /* Tabman.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Tabman.framework; path = ../Carthage/Build/iOS/Tabman.framework; sourceTree = ""; }; 57 | 46426508217E41E10001C4AF /* MessagesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesViewController.swift; sourceTree = ""; }; 58 | 4642650D217E42270001C4AF /* ProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = ""; }; 59 | 4642650F217E42A60001C4AF /* Profile.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Profile.storyboard; sourceTree = ""; }; 60 | 46426511217E42BA0001C4AF /* Messages.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Messages.storyboard; sourceTree = ""; }; 61 | 46426514217E42F20001C4AF /* MatchesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchesViewController.swift; sourceTree = ""; }; 62 | 46426516217E43040001C4AF /* Matches.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Matches.storyboard; sourceTree = ""; }; 63 | 46D36A4C218614CC0013635D /* MessagesMessageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesMessageCell.swift; sourceTree = ""; }; 64 | 46D36A4E218614D40013635D /* MessagesMessageCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MessagesMessageCell.xib; sourceTree = ""; }; 65 | 46D36A50218617ED0013635D /* MessagesFeedCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesFeedCell.swift; sourceTree = ""; }; 66 | 46D36A52218617F60013635D /* MessagesFeedCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MessagesFeedCell.xib; sourceTree = ""; }; 67 | /* End PBXFileReference section */ 68 | 69 | /* Begin PBXFrameworksBuildPhase section */ 70 | 464264E8217E3FCD0001C4AF /* Frameworks */ = { 71 | isa = PBXFrameworksBuildPhase; 72 | buildActionMask = 2147483647; 73 | files = ( 74 | 46F12DF823292C3B000EC76A /* Tabman in Frameworks */, 75 | ); 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | /* End PBXFrameworksBuildPhase section */ 79 | 80 | /* Begin PBXGroup section */ 81 | 4612CD4E217E43C600C1B4F7 /* Resources */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 464264F5217E3FCF0001C4AF /* Assets.xcassets */, 85 | 464264F7217E3FCF0001C4AF /* LaunchScreen.storyboard */, 86 | 464264FA217E3FCF0001C4AF /* Info.plist */, 87 | 4612CD662180FFE900C1B4F7 /* TinderColors.swift */, 88 | ); 89 | name = Resources; 90 | sourceTree = ""; 91 | }; 92 | 4612CD4F217E5BE600C1B4F7 /* Bars */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 46D36A5421861BE90013635D /* TinderBar */, 96 | 46D36A5521861BF40013635D /* MessagesBar */, 97 | ); 98 | path = Bars; 99 | sourceTree = ""; 100 | }; 101 | 4612CD68218101CD00C1B4F7 /* Utilities */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 4612CD69218101EC00C1B4F7 /* UIColor+Interpolation.swift */, 105 | ); 106 | path = Utilities; 107 | sourceTree = ""; 108 | }; 109 | 464264E2217E3FCD0001C4AF = { 110 | isa = PBXGroup; 111 | children = ( 112 | 464264ED217E3FCD0001C4AF /* Tinderbar */, 113 | 464264EC217E3FCD0001C4AF /* Products */, 114 | 46426500217E40B00001C4AF /* Frameworks */, 115 | ); 116 | sourceTree = ""; 117 | }; 118 | 464264EC217E3FCD0001C4AF /* Products */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 464264EB217E3FCD0001C4AF /* Tinderbar.app */, 122 | ); 123 | name = Products; 124 | sourceTree = ""; 125 | }; 126 | 464264ED217E3FCD0001C4AF /* Tinderbar */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 464264EE217E3FCD0001C4AF /* AppDelegate.swift */, 130 | 464264F2217E3FCD0001C4AF /* Root.storyboard */, 131 | 4612CD4C217E439400C1B4F7 /* RootTabViewController.swift */, 132 | 4612CD4F217E5BE600C1B4F7 /* Bars */, 133 | 4642650A217E41F30001C4AF /* ViewControllers */, 134 | 4612CD68218101CD00C1B4F7 /* Utilities */, 135 | 4612CD4E217E43C600C1B4F7 /* Resources */, 136 | ); 137 | path = Tinderbar; 138 | sourceTree = ""; 139 | }; 140 | 46426500217E40B00001C4AF /* Frameworks */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | 46426502217E40B00001C4AF /* AutoInsetter.framework */, 144 | 46426501217E40B00001C4AF /* Pageboy.framework */, 145 | 46426503217E40B00001C4AF /* Tabman.framework */, 146 | ); 147 | name = Frameworks; 148 | sourceTree = ""; 149 | }; 150 | 4642650A217E41F30001C4AF /* ViewControllers */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | 4642650C217E42110001C4AF /* Profile */, 154 | 46426513217E42DB0001C4AF /* Matches */, 155 | 4642650B217E41FC0001C4AF /* Messages */, 156 | ); 157 | path = ViewControllers; 158 | sourceTree = ""; 159 | }; 160 | 4642650B217E41FC0001C4AF /* Messages */ = { 161 | isa = PBXGroup; 162 | children = ( 163 | 46426511217E42BA0001C4AF /* Messages.storyboard */, 164 | 4612CD6B2181058900C1B4F7 /* MessagesTabViewController.swift */, 165 | 46426508217E41E10001C4AF /* MessagesViewController.swift */, 166 | 4612CD6D218105AC00C1B4F7 /* MessagesFeedViewController.swift */, 167 | 46D36A4B218614BF0013635D /* Views */, 168 | ); 169 | path = Messages; 170 | sourceTree = ""; 171 | }; 172 | 4642650C217E42110001C4AF /* Profile */ = { 173 | isa = PBXGroup; 174 | children = ( 175 | 4642650F217E42A60001C4AF /* Profile.storyboard */, 176 | 4642650D217E42270001C4AF /* ProfileViewController.swift */, 177 | ); 178 | path = Profile; 179 | sourceTree = ""; 180 | }; 181 | 46426513217E42DB0001C4AF /* Matches */ = { 182 | isa = PBXGroup; 183 | children = ( 184 | 46426516217E43040001C4AF /* Matches.storyboard */, 185 | 46426514217E42F20001C4AF /* MatchesViewController.swift */, 186 | ); 187 | path = Matches; 188 | sourceTree = ""; 189 | }; 190 | 46D36A4B218614BF0013635D /* Views */ = { 191 | isa = PBXGroup; 192 | children = ( 193 | 46D36A4C218614CC0013635D /* MessagesMessageCell.swift */, 194 | 46D36A4E218614D40013635D /* MessagesMessageCell.xib */, 195 | 46D36A50218617ED0013635D /* MessagesFeedCell.swift */, 196 | 46D36A52218617F60013635D /* MessagesFeedCell.xib */, 197 | ); 198 | path = Views; 199 | sourceTree = ""; 200 | }; 201 | 46D36A5421861BE90013635D /* TinderBar */ = { 202 | isa = PBXGroup; 203 | children = ( 204 | 4612CD50217E5BF500C1B4F7 /* TinderBar.swift */, 205 | 4612CD52217E5C0400C1B4F7 /* TinderBarLayout.swift */, 206 | 4612CD642180EB7800C1B4F7 /* TinderBarButtonContainer.swift */, 207 | 4612CD622180E70B00C1B4F7 /* TinderBarButton.swift */, 208 | ); 209 | path = TinderBar; 210 | sourceTree = ""; 211 | }; 212 | 46D36A5521861BF40013635D /* MessagesBar */ = { 213 | isa = PBXGroup; 214 | children = ( 215 | 4612CD6F218106CF00C1B4F7 /* MessagesBar.swift */, 216 | ); 217 | path = MessagesBar; 218 | sourceTree = ""; 219 | }; 220 | /* End PBXGroup section */ 221 | 222 | /* Begin PBXNativeTarget section */ 223 | 464264EA217E3FCD0001C4AF /* Tinderbar */ = { 224 | isa = PBXNativeTarget; 225 | buildConfigurationList = 464264FD217E3FCF0001C4AF /* Build configuration list for PBXNativeTarget "Tinderbar" */; 226 | buildPhases = ( 227 | 464264E7217E3FCD0001C4AF /* Sources */, 228 | 464264E8217E3FCD0001C4AF /* Frameworks */, 229 | 464264E9217E3FCD0001C4AF /* Resources */, 230 | ); 231 | buildRules = ( 232 | ); 233 | dependencies = ( 234 | ); 235 | name = Tinderbar; 236 | packageProductDependencies = ( 237 | 46F12DF723292C3B000EC76A /* Tabman */, 238 | ); 239 | productName = Tinderbar; 240 | productReference = 464264EB217E3FCD0001C4AF /* Tinderbar.app */; 241 | productType = "com.apple.product-type.application"; 242 | }; 243 | /* End PBXNativeTarget section */ 244 | 245 | /* Begin PBXProject section */ 246 | 464264E3217E3FCD0001C4AF /* Project object */ = { 247 | isa = PBXProject; 248 | attributes = { 249 | BuildIndependentTargetsInParallel = YES; 250 | LastSwiftUpdateCheck = 1000; 251 | LastUpgradeCheck = 1430; 252 | ORGANIZATIONNAME = "UI At Six"; 253 | TargetAttributes = { 254 | 464264EA217E3FCD0001C4AF = { 255 | CreatedOnToolsVersion = 10.0; 256 | }; 257 | }; 258 | }; 259 | buildConfigurationList = 464264E6217E3FCD0001C4AF /* Build configuration list for PBXProject "Tinderbar" */; 260 | compatibilityVersion = "Xcode 9.3"; 261 | developmentRegion = en; 262 | hasScannedForEncodings = 0; 263 | knownRegions = ( 264 | en, 265 | Base, 266 | ); 267 | mainGroup = 464264E2217E3FCD0001C4AF; 268 | packageReferences = ( 269 | 46F12DF623292C3B000EC76A /* XCRemoteSwiftPackageReference "Tabman" */, 270 | ); 271 | productRefGroup = 464264EC217E3FCD0001C4AF /* Products */; 272 | projectDirPath = ""; 273 | projectRoot = ""; 274 | targets = ( 275 | 464264EA217E3FCD0001C4AF /* Tinderbar */, 276 | ); 277 | }; 278 | /* End PBXProject section */ 279 | 280 | /* Begin PBXResourcesBuildPhase section */ 281 | 464264E9217E3FCD0001C4AF /* Resources */ = { 282 | isa = PBXResourcesBuildPhase; 283 | buildActionMask = 2147483647; 284 | files = ( 285 | 464264F9217E3FCF0001C4AF /* LaunchScreen.storyboard in Resources */, 286 | 46D36A53218617F60013635D /* MessagesFeedCell.xib in Resources */, 287 | 464264F6217E3FCF0001C4AF /* Assets.xcassets in Resources */, 288 | 46426517217E43040001C4AF /* Matches.storyboard in Resources */, 289 | 46426510217E42A60001C4AF /* Profile.storyboard in Resources */, 290 | 46426512217E42BA0001C4AF /* Messages.storyboard in Resources */, 291 | 464264F4217E3FCD0001C4AF /* Root.storyboard in Resources */, 292 | 46D36A4F218614D40013635D /* MessagesMessageCell.xib in Resources */, 293 | ); 294 | runOnlyForDeploymentPostprocessing = 0; 295 | }; 296 | /* End PBXResourcesBuildPhase section */ 297 | 298 | /* Begin PBXSourcesBuildPhase section */ 299 | 464264E7217E3FCD0001C4AF /* Sources */ = { 300 | isa = PBXSourcesBuildPhase; 301 | buildActionMask = 2147483647; 302 | files = ( 303 | 4612CD6C2181058900C1B4F7 /* MessagesTabViewController.swift in Sources */, 304 | 4642650E217E42270001C4AF /* ProfileViewController.swift in Sources */, 305 | 46D36A4D218614CC0013635D /* MessagesMessageCell.swift in Sources */, 306 | 46426509217E41E10001C4AF /* MessagesViewController.swift in Sources */, 307 | 4612CD53217E5C0400C1B4F7 /* TinderBarLayout.swift in Sources */, 308 | 4612CD6E218105AC00C1B4F7 /* MessagesFeedViewController.swift in Sources */, 309 | 4612CD672180FFE900C1B4F7 /* TinderColors.swift in Sources */, 310 | 46426515217E42F20001C4AF /* MatchesViewController.swift in Sources */, 311 | 4612CD70218106CF00C1B4F7 /* MessagesBar.swift in Sources */, 312 | 4612CD51217E5BF500C1B4F7 /* TinderBar.swift in Sources */, 313 | 464264EF217E3FCD0001C4AF /* AppDelegate.swift in Sources */, 314 | 4612CD4D217E439400C1B4F7 /* RootTabViewController.swift in Sources */, 315 | 4612CD652180EB7800C1B4F7 /* TinderBarButtonContainer.swift in Sources */, 316 | 46D36A51218617ED0013635D /* MessagesFeedCell.swift in Sources */, 317 | 4612CD6A218101EC00C1B4F7 /* UIColor+Interpolation.swift in Sources */, 318 | 4612CD632180E70B00C1B4F7 /* TinderBarButton.swift in Sources */, 319 | ); 320 | runOnlyForDeploymentPostprocessing = 0; 321 | }; 322 | /* End PBXSourcesBuildPhase section */ 323 | 324 | /* Begin PBXVariantGroup section */ 325 | 464264F2217E3FCD0001C4AF /* Root.storyboard */ = { 326 | isa = PBXVariantGroup; 327 | children = ( 328 | 464264F3217E3FCD0001C4AF /* Base */, 329 | ); 330 | name = Root.storyboard; 331 | sourceTree = ""; 332 | }; 333 | 464264F7217E3FCF0001C4AF /* LaunchScreen.storyboard */ = { 334 | isa = PBXVariantGroup; 335 | children = ( 336 | 464264F8217E3FCF0001C4AF /* Base */, 337 | ); 338 | name = LaunchScreen.storyboard; 339 | sourceTree = ""; 340 | }; 341 | /* End PBXVariantGroup section */ 342 | 343 | /* Begin XCBuildConfiguration section */ 344 | 464264FB217E3FCF0001C4AF /* Debug */ = { 345 | isa = XCBuildConfiguration; 346 | buildSettings = { 347 | ALWAYS_SEARCH_USER_PATHS = NO; 348 | CLANG_ANALYZER_NONNULL = YES; 349 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 350 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 351 | CLANG_CXX_LIBRARY = "libc++"; 352 | CLANG_ENABLE_MODULES = YES; 353 | CLANG_ENABLE_OBJC_ARC = YES; 354 | CLANG_ENABLE_OBJC_WEAK = YES; 355 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 356 | CLANG_WARN_BOOL_CONVERSION = YES; 357 | CLANG_WARN_COMMA = YES; 358 | CLANG_WARN_CONSTANT_CONVERSION = YES; 359 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 360 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 361 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 362 | CLANG_WARN_EMPTY_BODY = YES; 363 | CLANG_WARN_ENUM_CONVERSION = YES; 364 | CLANG_WARN_INFINITE_RECURSION = YES; 365 | CLANG_WARN_INT_CONVERSION = YES; 366 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 367 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 368 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 369 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 370 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 371 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 372 | CLANG_WARN_STRICT_PROTOTYPES = YES; 373 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 374 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 375 | CLANG_WARN_UNREACHABLE_CODE = YES; 376 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 377 | CODE_SIGN_IDENTITY = "iPhone Developer"; 378 | COPY_PHASE_STRIP = NO; 379 | DEBUG_INFORMATION_FORMAT = dwarf; 380 | ENABLE_STRICT_OBJC_MSGSEND = YES; 381 | ENABLE_TESTABILITY = YES; 382 | GCC_C_LANGUAGE_STANDARD = gnu11; 383 | GCC_DYNAMIC_NO_PIC = NO; 384 | GCC_NO_COMMON_BLOCKS = YES; 385 | GCC_OPTIMIZATION_LEVEL = 0; 386 | GCC_PREPROCESSOR_DEFINITIONS = ( 387 | "DEBUG=1", 388 | "$(inherited)", 389 | ); 390 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 391 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 392 | GCC_WARN_UNDECLARED_SELECTOR = YES; 393 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 394 | GCC_WARN_UNUSED_FUNCTION = YES; 395 | GCC_WARN_UNUSED_VARIABLE = YES; 396 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 397 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 398 | MTL_FAST_MATH = YES; 399 | ONLY_ACTIVE_ARCH = YES; 400 | SDKROOT = iphoneos; 401 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 402 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 403 | }; 404 | name = Debug; 405 | }; 406 | 464264FC217E3FCF0001C4AF /* Release */ = { 407 | isa = XCBuildConfiguration; 408 | buildSettings = { 409 | ALWAYS_SEARCH_USER_PATHS = NO; 410 | CLANG_ANALYZER_NONNULL = YES; 411 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 412 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 413 | CLANG_CXX_LIBRARY = "libc++"; 414 | CLANG_ENABLE_MODULES = YES; 415 | CLANG_ENABLE_OBJC_ARC = YES; 416 | CLANG_ENABLE_OBJC_WEAK = YES; 417 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 418 | CLANG_WARN_BOOL_CONVERSION = YES; 419 | CLANG_WARN_COMMA = YES; 420 | CLANG_WARN_CONSTANT_CONVERSION = YES; 421 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 422 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 423 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 424 | CLANG_WARN_EMPTY_BODY = YES; 425 | CLANG_WARN_ENUM_CONVERSION = YES; 426 | CLANG_WARN_INFINITE_RECURSION = YES; 427 | CLANG_WARN_INT_CONVERSION = YES; 428 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 429 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 430 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 431 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 432 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 433 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 434 | CLANG_WARN_STRICT_PROTOTYPES = YES; 435 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 436 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 437 | CLANG_WARN_UNREACHABLE_CODE = YES; 438 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 439 | CODE_SIGN_IDENTITY = "iPhone Developer"; 440 | COPY_PHASE_STRIP = NO; 441 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 442 | ENABLE_NS_ASSERTIONS = NO; 443 | ENABLE_STRICT_OBJC_MSGSEND = YES; 444 | GCC_C_LANGUAGE_STANDARD = gnu11; 445 | GCC_NO_COMMON_BLOCKS = YES; 446 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 447 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 448 | GCC_WARN_UNDECLARED_SELECTOR = YES; 449 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 450 | GCC_WARN_UNUSED_FUNCTION = YES; 451 | GCC_WARN_UNUSED_VARIABLE = YES; 452 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 453 | MTL_ENABLE_DEBUG_INFO = NO; 454 | MTL_FAST_MATH = YES; 455 | SDKROOT = iphoneos; 456 | SWIFT_COMPILATION_MODE = wholemodule; 457 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 458 | VALIDATE_PRODUCT = YES; 459 | }; 460 | name = Release; 461 | }; 462 | 464264FE217E3FCF0001C4AF /* Debug */ = { 463 | isa = XCBuildConfiguration; 464 | buildSettings = { 465 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 466 | CODE_SIGN_STYLE = Automatic; 467 | INFOPLIST_FILE = Tinderbar/Info.plist; 468 | LD_RUNPATH_SEARCH_PATHS = ( 469 | "$(inherited)", 470 | "@executable_path/Frameworks", 471 | ); 472 | PRODUCT_BUNDLE_IDENTIFIER = com.uias.Tinderbar; 473 | PRODUCT_NAME = "$(TARGET_NAME)"; 474 | SWIFT_VERSION = 5.0; 475 | TARGETED_DEVICE_FAMILY = 1; 476 | }; 477 | name = Debug; 478 | }; 479 | 464264FF217E3FCF0001C4AF /* Release */ = { 480 | isa = XCBuildConfiguration; 481 | buildSettings = { 482 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 483 | CODE_SIGN_STYLE = Automatic; 484 | INFOPLIST_FILE = Tinderbar/Info.plist; 485 | LD_RUNPATH_SEARCH_PATHS = ( 486 | "$(inherited)", 487 | "@executable_path/Frameworks", 488 | ); 489 | PRODUCT_BUNDLE_IDENTIFIER = com.uias.Tinderbar; 490 | PRODUCT_NAME = "$(TARGET_NAME)"; 491 | SWIFT_VERSION = 5.0; 492 | TARGETED_DEVICE_FAMILY = 1; 493 | }; 494 | name = Release; 495 | }; 496 | /* End XCBuildConfiguration section */ 497 | 498 | /* Begin XCConfigurationList section */ 499 | 464264E6217E3FCD0001C4AF /* Build configuration list for PBXProject "Tinderbar" */ = { 500 | isa = XCConfigurationList; 501 | buildConfigurations = ( 502 | 464264FB217E3FCF0001C4AF /* Debug */, 503 | 464264FC217E3FCF0001C4AF /* Release */, 504 | ); 505 | defaultConfigurationIsVisible = 0; 506 | defaultConfigurationName = Release; 507 | }; 508 | 464264FD217E3FCF0001C4AF /* Build configuration list for PBXNativeTarget "Tinderbar" */ = { 509 | isa = XCConfigurationList; 510 | buildConfigurations = ( 511 | 464264FE217E3FCF0001C4AF /* Debug */, 512 | 464264FF217E3FCF0001C4AF /* Release */, 513 | ); 514 | defaultConfigurationIsVisible = 0; 515 | defaultConfigurationName = Release; 516 | }; 517 | /* End XCConfigurationList section */ 518 | 519 | /* Begin XCRemoteSwiftPackageReference section */ 520 | 46F12DF623292C3B000EC76A /* XCRemoteSwiftPackageReference "Tabman" */ = { 521 | isa = XCRemoteSwiftPackageReference; 522 | repositoryURL = "https://github.com/uias/Tabman"; 523 | requirement = { 524 | kind = upToNextMajorVersion; 525 | minimumVersion = 3.0.2; 526 | }; 527 | }; 528 | /* End XCRemoteSwiftPackageReference section */ 529 | 530 | /* Begin XCSwiftPackageProductDependency section */ 531 | 46F12DF723292C3B000EC76A /* Tabman */ = { 532 | isa = XCSwiftPackageProductDependency; 533 | package = 46F12DF623292C3B000EC76A /* XCRemoteSwiftPackageReference "Tabman" */; 534 | productName = Tabman; 535 | }; 536 | /* End XCSwiftPackageProductDependency section */ 537 | }; 538 | rootObject = 464264E3217E3FCD0001C4AF /* Project object */; 539 | } 540 | -------------------------------------------------------------------------------- /Sources/Tinderbar.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sources/Tinderbar.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Sources/Tinderbar/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Tinderbar 4 | // 5 | // Created by Merrick Sapsford on 22/10/2018. 6 | // Copyright © 2018 UI At Six. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Sources/Tinderbar/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "app_icon-2.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "app_icon-1.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "1024x1024", 47 | "idiom" : "ios-marketing", 48 | "filename" : "app_icon.png", 49 | "scale" : "1x" 50 | } 51 | ], 52 | "info" : { 53 | "version" : 1, 54 | "author" : "xcode" 55 | } 56 | } -------------------------------------------------------------------------------- /Sources/Tinderbar/Assets.xcassets/AppIcon.appiconset/app_icon-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uias/Tinderbar/a10dc9e8a7f456846bd882978ccefb232ffd6959/Sources/Tinderbar/Assets.xcassets/AppIcon.appiconset/app_icon-1.png -------------------------------------------------------------------------------- /Sources/Tinderbar/Assets.xcassets/AppIcon.appiconset/app_icon-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uias/Tinderbar/a10dc9e8a7f456846bd882978ccefb232ffd6959/Sources/Tinderbar/Assets.xcassets/AppIcon.appiconset/app_icon-2.png -------------------------------------------------------------------------------- /Sources/Tinderbar/Assets.xcassets/AppIcon.appiconset/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uias/Tinderbar/a10dc9e8a7f456846bd882978ccefb232ffd6959/Sources/Tinderbar/Assets.xcassets/AppIcon.appiconset/app_icon.png -------------------------------------------------------------------------------- /Sources/Tinderbar/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Sources/Tinderbar/Assets.xcassets/ic_launch_logo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "ic_launch_logo.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "ic_launch_logo@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "ic_launch_logo@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Sources/Tinderbar/Assets.xcassets/ic_launch_logo.imageset/ic_launch_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uias/Tinderbar/a10dc9e8a7f456846bd882978ccefb232ffd6959/Sources/Tinderbar/Assets.xcassets/ic_launch_logo.imageset/ic_launch_logo.png -------------------------------------------------------------------------------- /Sources/Tinderbar/Assets.xcassets/ic_launch_logo.imageset/ic_launch_logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uias/Tinderbar/a10dc9e8a7f456846bd882978ccefb232ffd6959/Sources/Tinderbar/Assets.xcassets/ic_launch_logo.imageset/ic_launch_logo@2x.png -------------------------------------------------------------------------------- /Sources/Tinderbar/Assets.xcassets/ic_launch_logo.imageset/ic_launch_logo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uias/Tinderbar/a10dc9e8a7f456846bd882978ccefb232ffd6959/Sources/Tinderbar/Assets.xcassets/ic_launch_logo.imageset/ic_launch_logo@3x.png -------------------------------------------------------------------------------- /Sources/Tinderbar/Assets.xcassets/ic_matches.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "ic_tinder.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template", 14 | "preserves-vector-representation" : true 15 | } 16 | } -------------------------------------------------------------------------------- /Sources/Tinderbar/Assets.xcassets/ic_matches.imageset/ic_tinder.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uias/Tinderbar/a10dc9e8a7f456846bd882978ccefb232ffd6959/Sources/Tinderbar/Assets.xcassets/ic_matches.imageset/ic_tinder.pdf -------------------------------------------------------------------------------- /Sources/Tinderbar/Assets.xcassets/ic_messages.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "ic_messages.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template", 14 | "preserves-vector-representation" : true 15 | } 16 | } -------------------------------------------------------------------------------- /Sources/Tinderbar/Assets.xcassets/ic_messages.imageset/ic_messages.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uias/Tinderbar/a10dc9e8a7f456846bd882978ccefb232ffd6959/Sources/Tinderbar/Assets.xcassets/ic_messages.imageset/ic_messages.pdf -------------------------------------------------------------------------------- /Sources/Tinderbar/Assets.xcassets/ic_profile.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "ic_profile.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "template-rendering-intent" : "template", 14 | "preserves-vector-representation" : true 15 | } 16 | } -------------------------------------------------------------------------------- /Sources/Tinderbar/Assets.xcassets/ic_profile.imageset/ic_profile.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uias/Tinderbar/a10dc9e8a7f456846bd882978ccefb232ffd6959/Sources/Tinderbar/Assets.xcassets/ic_profile.imageset/ic_profile.pdf -------------------------------------------------------------------------------- /Sources/Tinderbar/Bars/MessagesBar/MessagesBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessagesBar.swift 3 | // Tinderbar 4 | // 5 | // Created by Merrick Sapsford on 24/10/2018. 6 | // Copyright © 2018 UI At Six. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Tabman 11 | 12 | class MessagesBar { 13 | 14 | typealias BarType = TMBarView 15 | 16 | static func make() -> BarType { 17 | let bar = BarType() 18 | 19 | bar.layout.contentMode = .fit 20 | bar.buttons.customize { (button) in 21 | button.selectedTintColor = TinderColors.primaryTint 22 | button.tintColor = TinderColors.unselectedGray 23 | button.font = UIFont.systemFont(ofSize: 19, weight: .semibold) 24 | } 25 | 26 | bar.backgroundView.style = .flat(color: .white) 27 | 28 | return bar 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /Sources/Tinderbar/Bars/TinderBar/TinderBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TinderBar.swift 3 | // Tinderbar 4 | // 5 | // Created by Merrick Sapsford on 22/10/2018. 6 | // Copyright © 2018 UI At Six. All rights reserved. 7 | // 8 | 9 | import Tabman 10 | 11 | class TinderBar { 12 | 13 | typealias BarType = TMBarView 14 | 15 | static func make() -> TMBar { 16 | let bar = BarType() 17 | 18 | bar.scrollMode = .swipe 19 | 20 | bar.buttons.customize { (button) in 21 | button.tintColor = TinderColors.primaryTint 22 | button.unselectedTintColor = TinderColors.unselectedGray 23 | } 24 | 25 | // Wrap in a 'navigation bar'. 26 | let navigationBar = bar.systemBar() 27 | navigationBar.backgroundStyle = .flat(color: .white) 28 | return navigationBar 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Tinderbar/Bars/TinderBar/TinderBarButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TinderBarButton.swift 3 | // Tinderbar 4 | // 5 | // Created by Merrick Sapsford on 24/10/2018. 6 | // Copyright © 2018 UI At Six. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Tabman 11 | 12 | class TinderBarButton: TMBarButton { 13 | 14 | // MARK: Defaults 15 | 16 | private struct Defaults { 17 | static let imageSize = CGSize(width: 36, height: 36) 18 | static let unselectedScale: CGFloat = 0.8 19 | } 20 | 21 | // MARK: Properties 22 | 23 | private let imageView = UIImageView() 24 | 25 | override var tintColor: UIColor! { 26 | didSet { 27 | update(for: self.selectionState) 28 | } 29 | } 30 | var unselectedTintColor: UIColor = .lightGray { 31 | didSet { 32 | update(for: self.selectionState) 33 | } 34 | } 35 | 36 | // MARK: Lifecycle 37 | 38 | override func layout(in view: UIView) { 39 | super.layout(in: view) 40 | 41 | adjustsAlphaOnSelection = false 42 | 43 | view.addSubview(imageView) 44 | imageView.translatesAutoresizingMaskIntoConstraints = false 45 | NSLayoutConstraint.activate([ 46 | imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor), 47 | imageView.topAnchor.constraint(equalTo: view.topAnchor), 48 | imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor), 49 | imageView.bottomAnchor.constraint(equalTo: view.bottomAnchor), 50 | imageView.widthAnchor.constraint(equalToConstant: Defaults.imageSize.width), 51 | imageView.heightAnchor.constraint(equalToConstant: Defaults.imageSize.height) 52 | ]) 53 | } 54 | 55 | override func populate(for item: TMBarItemable) { 56 | super.populate(for: item) 57 | 58 | imageView.image = item.image 59 | } 60 | 61 | override func update(for selectionState: TMBarButton.SelectionState) { 62 | super.update(for: selectionState) 63 | 64 | imageView.tintColor = unselectedTintColor.interpolate(with: tintColor, 65 | percent: selectionState.rawValue) 66 | 67 | let scale = 1.0 - ((1.0 - selectionState.rawValue) * (1.0 - Defaults.unselectedScale)) 68 | imageView.transform = CGAffineTransform(scaleX: scale, y: scale) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Sources/Tinderbar/Bars/TinderBar/TinderBarButtonContainer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TinderBarButtonContainer.swift 3 | // Tinderbar 4 | // 5 | // Created by Merrick Sapsford on 24/10/2018. 6 | // Copyright © 2018 UI At Six. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Tabman 11 | 12 | class TinderBarButtonContainer: UIView { 13 | 14 | // MARK: Properties 15 | 16 | internal let button: TMBarButton 17 | 18 | private var xAnchor: NSLayoutConstraint! 19 | 20 | var offsetDelta: CGFloat = 0.0 { 21 | didSet { 22 | xAnchor.constant = offsetDelta * (button.frame.size.width) 23 | } 24 | } 25 | 26 | // MARK: Init 27 | 28 | init(for button: TMBarButton) { 29 | self.button = button 30 | super.init(frame: .zero) 31 | initialize(with: button) 32 | } 33 | 34 | required init?(coder aDecoder: NSCoder) { 35 | fatalError("Not Supported") 36 | } 37 | 38 | private func initialize(with button: TMBarButton) { 39 | 40 | xAnchor = button.centerXAnchor.constraint(equalTo: centerXAnchor) 41 | 42 | addSubview(button) 43 | button.translatesAutoresizingMaskIntoConstraints = false 44 | NSLayoutConstraint.activate([ 45 | xAnchor, 46 | button.centerYAnchor.constraint(equalTo: centerYAnchor), 47 | button.topAnchor.constraint(equalTo: topAnchor), 48 | button.bottomAnchor.constraint(equalTo: bottomAnchor), 49 | button.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor), 50 | trailingAnchor.constraint(greaterThanOrEqualTo: button.trailingAnchor) 51 | ]) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Sources/Tinderbar/Bars/TinderBar/TinderBarLayout.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TinderBarLayout.swift 3 | // Tinderbar 4 | // 5 | // Created by Merrick Sapsford on 22/10/2018. 6 | // Copyright © 2018 UI At Six. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Tabman 11 | 12 | class TinderBarLayout: TMBarLayout { 13 | 14 | // MARK: Defaults 15 | 16 | private struct Defaults { 17 | static let contentInset = UIEdgeInsets(top: 4, left: 0, bottom: 10, right: 0) 18 | } 19 | 20 | // MARK: Properties 21 | 22 | private let stackView = UIStackView() 23 | private var containers = [TinderBarButtonContainer]() 24 | 25 | // MARK: Lifecycle 26 | 27 | override func layout(in view: UIView) { 28 | 29 | let paddedStackView = UIStackView() 30 | view.addSubview(paddedStackView) 31 | paddedStackView.translatesAutoresizingMaskIntoConstraints = false 32 | NSLayoutConstraint.activate([ 33 | paddedStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor), 34 | paddedStackView.topAnchor.constraint(equalTo: view.topAnchor), 35 | paddedStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor), 36 | paddedStackView.bottomAnchor.constraint(equalTo: view.bottomAnchor) 37 | ]) 38 | 39 | // Add two padding views to the leading/trailing edge of the main content stack view. 40 | // These views are 0.25 times the width of the content layout guide (1/4 of the view width). 41 | addPaddingView(multiplier: 0.25, to: paddedStackView) 42 | paddedStackView.addArrangedSubview(stackView) 43 | addPaddingView(multiplier: 0.25, to: paddedStackView) 44 | 45 | // Apply a default content inset. 46 | contentInset = Defaults.contentInset 47 | } 48 | 49 | override func insert(buttons: [TMBarButton], at index: Int) { 50 | buttons.forEach { (button) in 51 | let container = TinderBarButtonContainer(for: button) 52 | stackView.addArrangedSubview(container) 53 | containers.append(container) 54 | 55 | // Make button containers 1/2 the width of the layout guide (view width). 56 | container.widthAnchor.constraint(equalTo: layoutGuide.widthAnchor, multiplier: 0.5).isActive = true 57 | } 58 | } 59 | 60 | override func remove(buttons: [TMBarButton]) { 61 | let containers = stackView.arrangedSubviews.compactMap({ $0 as? TinderBarButtonContainer }) 62 | let containersToRemove = containers.filter({ buttons.contains($0.button) }) 63 | containersToRemove.forEach { (container) in 64 | stackView.removeArrangedSubview(container) 65 | container.removeFromSuperview() 66 | } 67 | } 68 | 69 | override func focusArea(for position: CGFloat, capacity: Int) -> CGRect { 70 | let range = buttonIndexRange(from: position, minimum: 0, maximum: capacity - 1) 71 | guard stackView.arrangedSubviews.count > range.upperBound else { 72 | return .zero 73 | } 74 | 75 | let lowerView = stackView.arrangedSubviews[range.lowerBound] 76 | let upperView = stackView.arrangedSubviews[range.upperBound] 77 | 78 | let lowerViewFrame = view.convert(lowerView.frame, from: stackView) 79 | let upperViewFrame = view.convert(upperView.frame, from: stackView) 80 | 81 | // Create an interpolated rect between the view that is detected as 'lower' (leading) 82 | // and the view that is 'upper' (trailing) for the current position. 83 | let interpolation = interpolatedRect(between: lowerViewFrame, 84 | and: upperViewFrame, 85 | position: position) 86 | 87 | // Update the offsets in the container. 88 | // This adjusts the 'center x' constraint of the button in the container, so that it is offsetted 89 | // correctly. Results in -1.0 when offsetted to the left, 0.0 when focussed and 1.0 when offsetted to the right. 90 | // This is then interpreted for the button width and increments/decrements the constraint constant appropriately. 91 | updateContainerOffsets(for: max(0.0, min(CGFloat(capacity) - 1.0, position))) 92 | 93 | return CGRect(x: lowerViewFrame.origin.x + interpolation.origin.x, 94 | y: 0.0, 95 | width: lowerViewFrame.size.width + interpolation.size.width, 96 | height: view.bounds.size.height) 97 | } 98 | 99 | private func updateContainerOffsets(for position: CGFloat) { 100 | for (index, container) in containers.enumerated() { 101 | let index = CGFloat(index) 102 | let positionDelta = max(-1.0, min(1.0, position - index)) 103 | container.offsetDelta = positionDelta 104 | } 105 | } 106 | 107 | // MARK: Utility 108 | 109 | @discardableResult 110 | private func addPaddingView(multiplier: CGFloat, to stack: UIStackView) -> UIView { 111 | let view = UIView() 112 | view.isUserInteractionEnabled = false 113 | stack.addArrangedSubview(view) 114 | view.translatesAutoresizingMaskIntoConstraints = false 115 | view.widthAnchor.constraint(equalTo: layoutGuide.widthAnchor, multiplier: multiplier).isActive = true 116 | return view 117 | } 118 | 119 | // MARK: Maths 120 | 121 | private func buttonIndexRange(from position: CGFloat, minimum: Int, maximum: Int) -> Range { 122 | guard maximum > minimum else { 123 | return 0 ..< 0 124 | } 125 | let lower = floor(position) 126 | let upper = ceil(position) 127 | let minimum = CGFloat(minimum) 128 | let maximum = CGFloat(maximum) 129 | 130 | return Int(max(minimum, min(maximum, lower))) ..< Int(min(maximum, max(minimum, upper))) 131 | } 132 | 133 | private func interpolatedRect(between frame: CGRect, and other: CGRect, position: CGFloat) -> CGRect { 134 | var integral: Float = 0.0 135 | let progress = CGFloat(modff(Float(position), &integral)) 136 | 137 | return CGRect(x: (other.origin.x - frame.origin.x) * progress, 138 | y: (other.origin.y - frame.origin.y) * progress, 139 | width: (other.size.width - frame.size.width) * progress, 140 | height: (other.size.height - frame.size.height) * progress) 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /Sources/Tinderbar/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Sources/Tinderbar/Base.lproj/Root.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 | -------------------------------------------------------------------------------- /Sources/Tinderbar/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Root 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIUserInterfaceStyle 43 | Light 44 | 45 | 46 | -------------------------------------------------------------------------------- /Sources/Tinderbar/RootTabViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RootTabViewController.swift 3 | // Tinderbar 4 | // 5 | // Created by Merrick Sapsford on 22/10/2018. 6 | // Copyright © 2018 UI At Six. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Tabman 11 | import Pageboy 12 | 13 | class RootTabViewController: TabmanViewController, PageboyViewControllerDataSource, TMBarDataSource { 14 | 15 | enum Tab: String, CaseIterable { 16 | case profile 17 | case matches 18 | case messages 19 | } 20 | 21 | private let tabItems = Tab.allCases.map({ BarItem(for: $0) }) 22 | private lazy var viewControllers = tabItems.compactMap({ $0.makeViewController() }) 23 | 24 | // MARK: Lifecycle 25 | 26 | override func viewDidLoad() { 27 | super.viewDidLoad() 28 | 29 | dataSource = self 30 | isScrollEnabled = false 31 | 32 | addBar(TinderBar.make(), dataSource: self, at: .top) 33 | } 34 | 35 | // MARK: PageboyViewControllerDataSource 36 | 37 | func numberOfViewControllers(in pageboyViewController: PageboyViewController) -> Int { 38 | return viewControllers.count 39 | } 40 | 41 | func viewController(for pageboyViewController: PageboyViewController, at index: PageboyViewController.PageIndex) -> UIViewController? { 42 | return viewControllers[index] 43 | } 44 | 45 | func defaultPage(for pageboyViewController: PageboyViewController) -> PageboyViewController.Page? { 46 | return .at(index: 1) 47 | } 48 | 49 | // MARK: TMBarDataSource 50 | 51 | func barItem(for bar: TMBar, at index: Int) -> TMBarItemable { 52 | return tabItems[index] 53 | } 54 | } 55 | 56 | private class BarItem: TMBarItemable { 57 | 58 | let tab: RootTabViewController.Tab 59 | 60 | init(for tab: RootTabViewController.Tab) { 61 | self.tab = tab 62 | } 63 | 64 | private var _title: String? { 65 | return tab.rawValue.capitalized 66 | } 67 | var title: String? { 68 | get { 69 | return _title 70 | } set {} 71 | } 72 | 73 | private var _image: UIImage? { 74 | return UIImage(named: "ic_\(tab.rawValue)") 75 | } 76 | var image: UIImage? { 77 | get { 78 | return _image 79 | } set {} 80 | } 81 | var selectedImage: UIImage? 82 | var badgeValue: String? 83 | 84 | func makeViewController() -> UIViewController? { 85 | let storyboardName: String 86 | switch tab { 87 | case .profile: 88 | storyboardName = "Profile" 89 | case .matches: 90 | storyboardName = "Matches" 91 | case .messages: 92 | storyboardName = "Messages" 93 | } 94 | 95 | return UIStoryboard(name: storyboardName, bundle: nil).instantiateInitialViewController() 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Sources/Tinderbar/TinderColors.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TinderColors.swift 3 | // Tinderbar 4 | // 5 | // Created by Merrick Sapsford on 24/10/2018. 6 | // Copyright © 2018 UI At Six. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | struct TinderColors { 12 | 13 | static var primaryTint: UIColor { 14 | return UIColor(red:0.99, green:0.31, blue:0.41, alpha:1.0) 15 | } 16 | 17 | static var unselectedGray: UIColor { 18 | return UIColor(red:0.85, green:0.87, blue:0.90, alpha:1.0) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Tinderbar/Utilities/UIColor+Interpolation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+Interpolation.swift 3 | // Tinderbar 4 | // 5 | // Created by Merrick Sapsford on 24/10/2018. 6 | // Copyright © 2018 UI At Six. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIColor { 12 | 13 | func interpolate(with other: UIColor, percent: CGFloat) -> UIColor? { 14 | return UIColor.interpolate(betweenColor: self, and: other, percent: percent) 15 | } 16 | 17 | static func interpolate(betweenColor colorA: UIColor, 18 | and colorB: UIColor, 19 | percent: CGFloat) -> UIColor? { 20 | var redA: CGFloat = 0.0 21 | var greenA: CGFloat = 0.0 22 | var blueA: CGFloat = 0.0 23 | var alphaA: CGFloat = 0.0 24 | guard colorA.getRed(&redA, green: &greenA, blue: &blueA, alpha: &alphaA) else { 25 | return nil 26 | } 27 | 28 | var redB: CGFloat = 0.0 29 | var greenB: CGFloat = 0.0 30 | var blueB: CGFloat = 0.0 31 | var alphaB: CGFloat = 0.0 32 | guard colorB.getRed(&redB, green: &greenB, blue: &blueB, alpha: &alphaB) else { 33 | return nil 34 | } 35 | 36 | let iRed = CGFloat(redA + percent * (redB - redA)) 37 | let iBlue = CGFloat(blueA + percent * (blueB - blueA)) 38 | let iGreen = CGFloat(greenA + percent * (greenB - greenA)) 39 | let iAlpha = CGFloat(alphaA + percent * (alphaB - alphaA)) 40 | 41 | return UIColor(red: iRed, green: iGreen, blue: iBlue, alpha: iAlpha) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/Tinderbar/ViewControllers/Matches/Matches.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 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /Sources/Tinderbar/ViewControllers/Matches/MatchesViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MatchesViewController.swift 3 | // Tinderbar 4 | // 5 | // Created by Merrick Sapsford on 22/10/2018. 6 | // Copyright © 2018 UI At Six. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MatchesViewController: UIViewController { 12 | 13 | @IBOutlet private weak var cardView: UIView! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | cardView.backgroundColor = TinderColors.unselectedGray 19 | cardView.layer.cornerRadius = 16.0 20 | } 21 | } 22 | 23 | @IBDesignable class MatchesActionButton: UIButton { 24 | 25 | override func awakeFromNib() { 26 | super.awakeFromNib() 27 | 28 | backgroundColor = TinderColors.unselectedGray 29 | } 30 | 31 | override func layoutSubviews() { 32 | super.layoutSubviews() 33 | 34 | layer.cornerRadius = bounds.size.width / 2.0 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/Tinderbar/ViewControllers/Messages/Messages.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 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /Sources/Tinderbar/ViewControllers/Messages/MessagesFeedViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessagesFeedViewController.swift 3 | // Tinderbar 4 | // 5 | // Created by Merrick Sapsford on 24/10/2018. 6 | // Copyright © 2018 UI At Six. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MessagesFeedViewController: UITableViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | tableView.contentInset = UIEdgeInsets(top: 16.0, left: 0.0, bottom: 0.0, right: 0.0) 17 | 18 | tableView.register(UINib(nibName: "MessagesFeedCell", bundle: nil), 19 | forCellReuseIdentifier: MessagesFeedCell.reuseIdentifier) 20 | } 21 | 22 | override func numberOfSections(in tableView: UITableView) -> Int { 23 | return 1 24 | } 25 | 26 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 27 | return 10 28 | } 29 | 30 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 31 | let cell = tableView.dequeueReusableCell(withIdentifier: MessagesFeedCell.reuseIdentifier, for: indexPath) 32 | cell.selectionStyle = .none 33 | return cell 34 | } 35 | 36 | override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 37 | return tableView.bounds.size.width * 1.2 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Tinderbar/ViewControllers/Messages/MessagesTabViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessagesTabViewController.swift 3 | // Tinderbar 4 | // 5 | // Created by Merrick Sapsford on 24/10/2018. 6 | // Copyright © 2018 UI At Six. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Tabman 11 | import Pageboy 12 | 13 | class MessagesTabViewController: TabmanViewController, PageboyViewControllerDataSource, TMBarDataSource { 14 | 15 | enum Tab: String, CaseIterable { 16 | case messages 17 | case feed 18 | } 19 | 20 | private let tabItems = Tab.allCases.map({ BarItem(for: $0) }) 21 | private lazy var viewControllers = tabItems.compactMap({ $0.makeViewController() }) 22 | 23 | let bar = MessagesBar.make() 24 | 25 | // MARK: Lifecycle 26 | 27 | override func viewDidLoad() { 28 | super.viewDidLoad() 29 | 30 | self.dataSource = self 31 | 32 | addBar(bar, dataSource: self, at: .top) 33 | } 34 | 35 | override func viewDidLayoutSubviews() { 36 | super.viewDidLayoutSubviews() 37 | 38 | bar.layer.masksToBounds = false 39 | bar.layer.shadowColor = UIColor.black.cgColor 40 | bar.layer.shadowOffset = CGSize(width: 0.0, height: 2.0) 41 | bar.layer.shadowOpacity = 0.1 42 | bar.layer.shadowPath = UIBezierPath(rect: bar.bounds).cgPath 43 | } 44 | 45 | // MARK: PageboyViewControllerDataSource 46 | 47 | func numberOfViewControllers(in pageboyViewController: PageboyViewController) -> Int { 48 | return viewControllers.count 49 | } 50 | 51 | func viewController(for pageboyViewController: PageboyViewController, at index: PageboyViewController.PageIndex) -> UIViewController? { 52 | return viewControllers[index] 53 | } 54 | 55 | func defaultPage(for pageboyViewController: PageboyViewController) -> PageboyViewController.Page? { 56 | return nil 57 | } 58 | 59 | // MARK: TMBarDataSource 60 | 61 | func barItem(for bar: TMBar, at index: Int) -> TMBarItemable { 62 | return tabItems[index] 63 | } 64 | } 65 | 66 | private class BarItem: TMBarItemable { 67 | 68 | let tab: MessagesTabViewController.Tab 69 | 70 | init(for tab: MessagesTabViewController.Tab) { 71 | self.tab = tab 72 | } 73 | 74 | private var _title: String { 75 | return tab.rawValue.capitalized 76 | } 77 | var title: String? { 78 | get { 79 | return _title 80 | } set {} 81 | } 82 | var image: UIImage? 83 | var selectedImage: UIImage? 84 | var badgeValue: String? 85 | 86 | func makeViewController() -> UIViewController? { 87 | let storyboard = UIStoryboard(name: "Messages", bundle: nil) 88 | let viewControllerId: String 89 | switch tab { 90 | case .messages: 91 | viewControllerId = "MessagesViewController" 92 | case .feed: 93 | viewControllerId = "MessagesFeedViewController" 94 | } 95 | 96 | return storyboard.instantiateViewController(withIdentifier: viewControllerId) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Sources/Tinderbar/ViewControllers/Messages/MessagesViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessagesViewController.swift 3 | // Tinderbar 4 | // 5 | // Created by Merrick Sapsford on 22/10/2018. 6 | // Copyright © 2018 UI At Six. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MessagesViewController: UITableViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | tableView.register(UINib(nibName: "MessagesMessageCell", bundle: nil), 17 | forCellReuseIdentifier: MessagesMessageCell.reuseIdentifier) 18 | } 19 | 20 | override func numberOfSections(in tableView: UITableView) -> Int { 21 | return 1 22 | } 23 | 24 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 25 | return 10 26 | } 27 | 28 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 29 | let cell = tableView.dequeueReusableCell(withIdentifier: MessagesMessageCell.reuseIdentifier, for: indexPath) 30 | cell.selectionStyle = .none 31 | return cell 32 | } 33 | 34 | override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 35 | return 96.0 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/Tinderbar/ViewControllers/Messages/Views/MessagesFeedCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessagesFeedCell.swift 3 | // Tinderbar 4 | // 5 | // Created by Merrick Sapsford on 28/10/2018. 6 | // Copyright © 2018 UI At Six. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MessagesFeedCell: UITableViewCell { 12 | 13 | static let reuseIdentifier = "MessagesFeedCell" 14 | 15 | @IBOutlet private weak var avatarView: UIView! 16 | @IBOutlet private weak var contentImageView: UIView! 17 | @IBOutlet private weak var nameLabel: UILabel! 18 | @IBOutlet private weak var actionLabel: UILabel! 19 | @IBOutlet private weak var dateLabel: UILabel! 20 | 21 | override func awakeFromNib() { 22 | super.awakeFromNib() 23 | 24 | contentImageView.backgroundColor = TinderColors.unselectedGray 25 | avatarView.backgroundColor = TinderColors.unselectedGray 26 | actionLabel.textColor = .lightGray 27 | dateLabel.textColor = .lightGray 28 | } 29 | 30 | override func layoutSubviews() { 31 | super.layoutSubviews() 32 | 33 | avatarView.layer.cornerRadius = avatarView.bounds.size.width / 2 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Tinderbar/ViewControllers/Messages/Views/MessagesFeedCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 40 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /Sources/Tinderbar/ViewControllers/Messages/Views/MessagesMessageCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessagesMessageCell.swift 3 | // Tinderbar 4 | // 5 | // Created by Merrick Sapsford on 28/10/2018. 6 | // Copyright © 2018 UI At Six. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MessagesMessageCell: UITableViewCell { 12 | 13 | static let reuseIdentifier = "MessagesMessageCell" 14 | 15 | @IBOutlet private weak var avatarView: UIView! 16 | @IBOutlet private weak var titleLabel: UILabel! 17 | @IBOutlet private weak var messageLabel: UILabel! 18 | 19 | override func awakeFromNib() { 20 | super.awakeFromNib() 21 | 22 | avatarView.backgroundColor = TinderColors.unselectedGray 23 | messageLabel.textColor = .lightGray 24 | } 25 | 26 | override func layoutSubviews() { 27 | super.layoutSubviews() 28 | 29 | avatarView.layer.cornerRadius = avatarView.bounds.size.width / 2 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Tinderbar/ViewControllers/Messages/Views/MessagesMessageCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 36 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /Sources/Tinderbar/ViewControllers/Profile/Profile.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 | 42 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /Sources/Tinderbar/ViewControllers/Profile/ProfileViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProfileViewController.swift 3 | // Tinderbar 4 | // 5 | // Created by Merrick Sapsford on 22/10/2018. 6 | // Copyright © 2018 UI At Six. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ProfileViewController: UIViewController { 12 | 13 | @IBOutlet private weak var contentView: UIView! 14 | private let contentViewMaskLayer = CAShapeLayer() 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | 19 | contentView.layer.mask = contentViewMaskLayer 20 | } 21 | 22 | override func viewDidLayoutSubviews() { 23 | super.viewDidLayoutSubviews() 24 | 25 | contentViewMaskLayer.frame = contentView.bounds 26 | contentViewMaskLayer.path = contentViewMaskPath(in: contentView.bounds).cgPath 27 | } 28 | } 29 | 30 | private extension ProfileViewController { 31 | 32 | private func contentViewMaskPath(in frame: CGRect) -> UIBezierPath { 33 | 34 | let curveOffset = frame.size.height / 6 35 | 36 | let path = UIBezierPath() 37 | path.move(to: .zero) 38 | path.addLine(to: CGPoint(x: frame.maxX, y: frame.minY)) 39 | path.addLine(to: CGPoint(x: frame.maxX, y: frame.maxY - curveOffset)) 40 | path.addQuadCurve(to: CGPoint(x: frame.minX, y: frame.maxY - curveOffset), 41 | controlPoint: CGPoint(x: frame.maxX / 2, y: frame.maxY)) 42 | path.close() 43 | return path 44 | } 45 | } 46 | 47 | @IBDesignable class ProfileActionButton: UIButton { 48 | 49 | override func awakeFromNib() { 50 | super.awakeFromNib() 51 | 52 | backgroundColor = TinderColors.unselectedGray 53 | } 54 | 55 | override func layoutSubviews() { 56 | super.layoutSubviews() 57 | 58 | layer.cornerRadius = bounds.size.width / 2.0 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Tinderbar.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uias/Tinderbar/a10dc9e8a7f456846bd882978ccefb232ffd6959/Tinderbar.sketch -------------------------------------------------------------------------------- /Tinderbar.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Tinderbar.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Tinderbar.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "pageboy", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/uias/Pageboy", 7 | "state" : { 8 | "revision" : "5522aa6ae88633f6c23cf504e9cd684e963822f1", 9 | "version" : "4.0.2" 10 | } 11 | }, 12 | { 13 | "identity" : "tabman", 14 | "kind" : "remoteSourceControl", 15 | "location" : "https://github.com/uias/Tabman", 16 | "state" : { 17 | "revision" : "e32c0d821b03566ed966753f941113883f268da0", 18 | "version" : "3.0.2" 19 | } 20 | } 21 | ], 22 | "version" : 2 23 | } 24 | --------------------------------------------------------------------------------