├── .gitignore ├── LICENSE ├── README.md ├── XTrello.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── XTrello ├── API │ ├── XTTrelloWrapper.h │ └── XTTrelloWrapper.m ├── Categories and Subclasses │ ├── NSArray+trelloAdditions.h │ ├── NSArray+trelloAdditions.m │ ├── NSColor+Hex.h │ ├── NSColor+Hex.m │ ├── NSDate+trelloAdditions.h │ ├── NSDate+trelloAdditions.m │ ├── NSDictionary+trelloAdditions.h │ ├── NSDictionary+trelloAdditions.m │ ├── NSMenuItem+boardDict.h │ ├── NSMenuItem+boardDict.m │ ├── NSString+trelloAdditions.h │ ├── NSString+trelloAdditions.m │ ├── NSView+trelloAdditions.h │ ├── NSView+trelloAdditions.m │ ├── XTMenuItem.h │ ├── XTMenuItem.m │ ├── XTTableView.h │ └── XTTableView.m ├── NSData+Split.h ├── NSData+Split.m ├── PureLayout │ ├── ALView+PureLayout.h │ ├── ALView+PureLayout.m │ ├── NSArray+PureLayout.h │ ├── NSArray+PureLayout.m │ ├── NSLayoutConstraint+PureLayout.h │ ├── NSLayoutConstraint+PureLayout.m │ ├── PureLayout+Internal.h │ ├── PureLayout.h │ └── PureLayoutDefines.h ├── View Classes │ ├── XTTagView.h │ ├── XTTagView.m │ ├── XTTagViewController.h │ ├── XTTagViewController.m │ ├── XTTrelloCardView.h │ └── XTTrelloCardView.m ├── XTModel.h ├── XTModel.m ├── XTProjectSetting.h ├── XTProjectSetting.m ├── XTWindowController.h ├── XTWindowController.m ├── XTWindowController.xib ├── XTrello-Info.plist ├── XTrello-Prefix.pch ├── XTrello.h ├── XTrello.m ├── XTrelloItem.h ├── XTrelloItem.m └── en.lproj │ └── InfoPlist.strings ├── add_labels.png ├── browser_window.png └── create_source_card.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Kevin Bradley 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | XTrello 2 | ======= 3 | 4 | Xcode plugin for native Trello board access. 5 | 6 | The initial setup process is a bit cumbersome, depending on the interest garnered in this plugin it will potentially be refined in the future. 7 | 8 | Setup Process. 9 | 10 | 1. Create trello account (if you don't have one already) at http://trello.com 11 | 2. Open this project in Xcode and build (it will build into the proper location) 12 | 3. Quit and Re-Open XCode 13 | 4. View -> Trello -> Show Trello Boards (this will show the preferences window if API Key / Session Token is missing) 14 | 5. Click "Fetch Key" 15 | 6. This will open up https://trello.com/1/appKey/generate in the native XTrello browser window and SHOULD copy your API key automatically, if it does not you will need to copy and paste it manually 16 | 7. (only needed if step 6 fails) Copy and paste your API Key into the second text field in the XTrello preferences window (Trello Key) 17 | 8. Click "Generate Token" 18 | 9. This will open the built in browser window in XTrello and ask you for permission for XTrello to access your trello boards 19 | 10. Click "Allow" 20 | 11. This should automatically populate the session token in the top text field (Trello Token) if it does not, copy and paste the session token (without the spaces) in the Trello Token text field. 21 | 12. View -> Trello -> Show Trello boards will now show your trello boards. 22 | 13. Enjoy! 23 | 24 | 25 | Adding card labels 26 | 27 | ![alt text](add_labels.png "Editing card labels") 28 | 29 | Creating cards referencing sections of source code 30 | 31 | ![alt text](create_source_card.png "Creating cards from source") 32 | 33 | Double clicking a card native browser window 34 | 35 | ![alt text](browser_window.png "Browser window from card double click") 36 | -------------------------------------------------------------------------------- /XTrello.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 322B727F19744E5700555109 /* XTWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 322B727D19744E5700555109 /* XTWindowController.m */; }; 11 | 322B728019744E5700555109 /* XTWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 322B727E19744E5700555109 /* XTWindowController.xib */; }; 12 | 322B728E19744F8900555109 /* NSArray+trelloAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 322B728319744F8900555109 /* NSArray+trelloAdditions.m */; }; 13 | 322B728F19744F8900555109 /* NSDictionary+trelloAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 322B728519744F8900555109 /* NSDictionary+trelloAdditions.m */; }; 14 | 322B729019744F8900555109 /* NSString+trelloAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 322B728719744F8900555109 /* NSString+trelloAdditions.m */; }; 15 | 322B729119744F8900555109 /* NSView+trelloAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 322B728919744F8900555109 /* NSView+trelloAdditions.m */; }; 16 | 322B729219744F8900555109 /* XTMenuItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 322B728B19744F8900555109 /* XTMenuItem.m */; }; 17 | 322B729319744F8900555109 /* XTTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 322B728D19744F8900555109 /* XTTableView.m */; }; 18 | 322B729B19744F9300555109 /* XTTagView.m in Sources */ = {isa = PBXBuildFile; fileRef = 322B729619744F9300555109 /* XTTagView.m */; }; 19 | 322B729C19744F9300555109 /* XTTagViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 322B729819744F9300555109 /* XTTagViewController.m */; }; 20 | 322B729D19744F9300555109 /* XTTrelloCardView.m in Sources */ = {isa = PBXBuildFile; fileRef = 322B729A19744F9300555109 /* XTTrelloCardView.m */; }; 21 | 322B72A119744FAB00555109 /* XTTrelloWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 322B72A019744FAB00555109 /* XTTrelloWrapper.m */; }; 22 | 3264F4F619744CF700E9E1B6 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3264F4F519744CF700E9E1B6 /* AppKit.framework */; }; 23 | 3264F4F819744CF700E9E1B6 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3264F4F719744CF700E9E1B6 /* Foundation.framework */; }; 24 | 3264F4FE19744CF700E9E1B6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3264F4FC19744CF700E9E1B6 /* InfoPlist.strings */; }; 25 | 3264F50119744CF700E9E1B6 /* XTrello.m in Sources */ = {isa = PBXBuildFile; fileRef = 3264F50019744CF700E9E1B6 /* XTrello.m */; }; 26 | 32871C05197831FF00277DEB /* NSDate+trelloAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 32871C04197831FF00277DEB /* NSDate+trelloAdditions.m */; }; 27 | 32CFDAA519749C050008F69A /* XTModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CFDAA219749C050008F69A /* XTModel.m */; }; 28 | 32CFDAA619749C050008F69A /* XTProjectSetting.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CFDAA419749C050008F69A /* XTProjectSetting.m */; }; 29 | 32CFDAA919749C560008F69A /* NSData+Split.m in Sources */ = {isa = PBXBuildFile; fileRef = 32CFDAA819749C560008F69A /* NSData+Split.m */; }; 30 | 32FEA9101975D02B008B3661 /* XTrelloItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FEA90F1975D02B008B3661 /* XTrelloItem.m */; }; 31 | 895236941A21539000719E09 /* NSColor+Hex.m in Sources */ = {isa = PBXBuildFile; fileRef = 895236931A21539000719E09 /* NSColor+Hex.m */; }; 32 | 89A7E8151DC330910047F32C /* NSMenuItem+boardDict.m in Sources */ = {isa = PBXBuildFile; fileRef = 89A7E8141DC330910047F32C /* NSMenuItem+boardDict.m */; }; 33 | 89F378B71D827FF9008D36CF /* ALView+PureLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 89F378AF1D827FF9008D36CF /* ALView+PureLayout.m */; }; 34 | 89F378B81D827FF9008D36CF /* NSArray+PureLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 89F378B11D827FF9008D36CF /* NSArray+PureLayout.m */; }; 35 | 89F378B91D827FF9008D36CF /* NSLayoutConstraint+PureLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 89F378B31D827FF9008D36CF /* NSLayoutConstraint+PureLayout.m */; }; 36 | /* End PBXBuildFile section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | 322B727C19744E5700555109 /* XTWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XTWindowController.h; sourceTree = ""; }; 40 | 322B727D19744E5700555109 /* XTWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XTWindowController.m; sourceTree = ""; }; 41 | 322B727E19744E5700555109 /* XTWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = XTWindowController.xib; sourceTree = ""; }; 42 | 322B728219744F8900555109 /* NSArray+trelloAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+trelloAdditions.h"; sourceTree = ""; }; 43 | 322B728319744F8900555109 /* NSArray+trelloAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+trelloAdditions.m"; sourceTree = ""; }; 44 | 322B728419744F8900555109 /* NSDictionary+trelloAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+trelloAdditions.h"; sourceTree = ""; }; 45 | 322B728519744F8900555109 /* NSDictionary+trelloAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+trelloAdditions.m"; sourceTree = ""; }; 46 | 322B728619744F8900555109 /* NSString+trelloAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+trelloAdditions.h"; sourceTree = ""; }; 47 | 322B728719744F8900555109 /* NSString+trelloAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+trelloAdditions.m"; sourceTree = ""; }; 48 | 322B728819744F8900555109 /* NSView+trelloAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSView+trelloAdditions.h"; sourceTree = ""; }; 49 | 322B728919744F8900555109 /* NSView+trelloAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSView+trelloAdditions.m"; sourceTree = ""; }; 50 | 322B728A19744F8900555109 /* XTMenuItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XTMenuItem.h; sourceTree = ""; }; 51 | 322B728B19744F8900555109 /* XTMenuItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XTMenuItem.m; sourceTree = ""; }; 52 | 322B728C19744F8900555109 /* XTTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XTTableView.h; sourceTree = ""; }; 53 | 322B728D19744F8900555109 /* XTTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XTTableView.m; sourceTree = ""; }; 54 | 322B729519744F9300555109 /* XTTagView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XTTagView.h; sourceTree = ""; }; 55 | 322B729619744F9300555109 /* XTTagView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XTTagView.m; sourceTree = ""; }; 56 | 322B729719744F9300555109 /* XTTagViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XTTagViewController.h; sourceTree = ""; }; 57 | 322B729819744F9300555109 /* XTTagViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XTTagViewController.m; sourceTree = ""; }; 58 | 322B729919744F9300555109 /* XTTrelloCardView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XTTrelloCardView.h; sourceTree = ""; }; 59 | 322B729A19744F9300555109 /* XTTrelloCardView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XTTrelloCardView.m; sourceTree = ""; }; 60 | 322B729F19744FAB00555109 /* XTTrelloWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XTTrelloWrapper.h; sourceTree = ""; }; 61 | 322B72A019744FAB00555109 /* XTTrelloWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XTTrelloWrapper.m; sourceTree = ""; }; 62 | 3264F4F219744CF700E9E1B6 /* XTrello.xcplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = XTrello.xcplugin; sourceTree = BUILT_PRODUCTS_DIR; }; 63 | 3264F4F519744CF700E9E1B6 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 64 | 3264F4F719744CF700E9E1B6 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 65 | 3264F4FB19744CF700E9E1B6 /* XTrello-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "XTrello-Info.plist"; sourceTree = ""; }; 66 | 3264F4FD19744CF700E9E1B6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 67 | 3264F4FF19744CF700E9E1B6 /* XTrello.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XTrello.h; sourceTree = ""; }; 68 | 3264F50019744CF700E9E1B6 /* XTrello.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XTrello.m; sourceTree = ""; }; 69 | 3264F50219744CF700E9E1B6 /* XTrello-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "XTrello-Prefix.pch"; sourceTree = ""; }; 70 | 32871C03197831FF00277DEB /* NSDate+trelloAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+trelloAdditions.h"; sourceTree = ""; }; 71 | 32871C04197831FF00277DEB /* NSDate+trelloAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+trelloAdditions.m"; sourceTree = ""; }; 72 | 32CFDAA119749C050008F69A /* XTModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XTModel.h; sourceTree = ""; }; 73 | 32CFDAA219749C050008F69A /* XTModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XTModel.m; sourceTree = ""; }; 74 | 32CFDAA319749C050008F69A /* XTProjectSetting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XTProjectSetting.h; sourceTree = ""; }; 75 | 32CFDAA419749C050008F69A /* XTProjectSetting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XTProjectSetting.m; sourceTree = ""; }; 76 | 32CFDAA719749C560008F69A /* NSData+Split.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSData+Split.h"; path = "../NSData+Split.h"; sourceTree = ""; }; 77 | 32CFDAA819749C560008F69A /* NSData+Split.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSData+Split.m"; path = "../NSData+Split.m"; sourceTree = ""; }; 78 | 32FEA90E1975D02B008B3661 /* XTrelloItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XTrelloItem.h; sourceTree = ""; }; 79 | 32FEA90F1975D02B008B3661 /* XTrelloItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XTrelloItem.m; sourceTree = ""; }; 80 | 895236921A21539000719E09 /* NSColor+Hex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSColor+Hex.h"; sourceTree = ""; }; 81 | 895236931A21539000719E09 /* NSColor+Hex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSColor+Hex.m"; sourceTree = ""; }; 82 | 89A7E8131DC330910047F32C /* NSMenuItem+boardDict.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMenuItem+boardDict.h"; sourceTree = ""; }; 83 | 89A7E8141DC330910047F32C /* NSMenuItem+boardDict.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMenuItem+boardDict.m"; sourceTree = ""; }; 84 | 89F378AE1D827FF9008D36CF /* ALView+PureLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ALView+PureLayout.h"; sourceTree = ""; }; 85 | 89F378AF1D827FF9008D36CF /* ALView+PureLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ALView+PureLayout.m"; sourceTree = ""; }; 86 | 89F378B01D827FF9008D36CF /* NSArray+PureLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+PureLayout.h"; sourceTree = ""; }; 87 | 89F378B11D827FF9008D36CF /* NSArray+PureLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+PureLayout.m"; sourceTree = ""; }; 88 | 89F378B21D827FF9008D36CF /* NSLayoutConstraint+PureLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSLayoutConstraint+PureLayout.h"; sourceTree = ""; }; 89 | 89F378B31D827FF9008D36CF /* NSLayoutConstraint+PureLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSLayoutConstraint+PureLayout.m"; sourceTree = ""; }; 90 | 89F378B41D827FF9008D36CF /* PureLayout+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "PureLayout+Internal.h"; sourceTree = ""; }; 91 | 89F378B51D827FF9008D36CF /* PureLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PureLayout.h; sourceTree = ""; }; 92 | 89F378B61D827FF9008D36CF /* PureLayoutDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PureLayoutDefines.h; sourceTree = ""; }; 93 | /* End PBXFileReference section */ 94 | 95 | /* Begin PBXFrameworksBuildPhase section */ 96 | 3264F4EF19744CF700E9E1B6 /* Frameworks */ = { 97 | isa = PBXFrameworksBuildPhase; 98 | buildActionMask = 2147483647; 99 | files = ( 100 | 3264F4F619744CF700E9E1B6 /* AppKit.framework in Frameworks */, 101 | 3264F4F819744CF700E9E1B6 /* Foundation.framework in Frameworks */, 102 | ); 103 | runOnlyForDeploymentPostprocessing = 0; 104 | }; 105 | /* End PBXFrameworksBuildPhase section */ 106 | 107 | /* Begin PBXGroup section */ 108 | 322B728119744F8900555109 /* Categories and Subclasses */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 895236921A21539000719E09 /* NSColor+Hex.h */, 112 | 895236931A21539000719E09 /* NSColor+Hex.m */, 113 | 32CFDAA719749C560008F69A /* NSData+Split.h */, 114 | 32CFDAA819749C560008F69A /* NSData+Split.m */, 115 | 322B728219744F8900555109 /* NSArray+trelloAdditions.h */, 116 | 322B728319744F8900555109 /* NSArray+trelloAdditions.m */, 117 | 322B728419744F8900555109 /* NSDictionary+trelloAdditions.h */, 118 | 322B728519744F8900555109 /* NSDictionary+trelloAdditions.m */, 119 | 322B728619744F8900555109 /* NSString+trelloAdditions.h */, 120 | 322B728719744F8900555109 /* NSString+trelloAdditions.m */, 121 | 322B728819744F8900555109 /* NSView+trelloAdditions.h */, 122 | 322B728919744F8900555109 /* NSView+trelloAdditions.m */, 123 | 89A7E8131DC330910047F32C /* NSMenuItem+boardDict.h */, 124 | 89A7E8141DC330910047F32C /* NSMenuItem+boardDict.m */, 125 | 322B728A19744F8900555109 /* XTMenuItem.h */, 126 | 322B728B19744F8900555109 /* XTMenuItem.m */, 127 | 322B728C19744F8900555109 /* XTTableView.h */, 128 | 322B728D19744F8900555109 /* XTTableView.m */, 129 | 32871C03197831FF00277DEB /* NSDate+trelloAdditions.h */, 130 | 32871C04197831FF00277DEB /* NSDate+trelloAdditions.m */, 131 | ); 132 | path = "Categories and Subclasses"; 133 | sourceTree = ""; 134 | }; 135 | 322B729419744F9300555109 /* View Classes */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | 322B729519744F9300555109 /* XTTagView.h */, 139 | 322B729619744F9300555109 /* XTTagView.m */, 140 | 322B729719744F9300555109 /* XTTagViewController.h */, 141 | 322B729819744F9300555109 /* XTTagViewController.m */, 142 | 322B729919744F9300555109 /* XTTrelloCardView.h */, 143 | 322B729A19744F9300555109 /* XTTrelloCardView.m */, 144 | ); 145 | name = "View Classes"; 146 | path = "XTrello/View Classes"; 147 | sourceTree = SOURCE_ROOT; 148 | }; 149 | 322B729E19744FAB00555109 /* API */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | 322B729F19744FAB00555109 /* XTTrelloWrapper.h */, 153 | 322B72A019744FAB00555109 /* XTTrelloWrapper.m */, 154 | ); 155 | path = API; 156 | sourceTree = ""; 157 | }; 158 | 3264F4E919744CF700E9E1B6 = { 159 | isa = PBXGroup; 160 | children = ( 161 | 3264F4F919744CF700E9E1B6 /* XTrello */, 162 | 3264F4F419744CF700E9E1B6 /* Frameworks */, 163 | 3264F4F319744CF700E9E1B6 /* Products */, 164 | ); 165 | sourceTree = ""; 166 | }; 167 | 3264F4F319744CF700E9E1B6 /* Products */ = { 168 | isa = PBXGroup; 169 | children = ( 170 | 3264F4F219744CF700E9E1B6 /* XTrello.xcplugin */, 171 | ); 172 | name = Products; 173 | sourceTree = ""; 174 | }; 175 | 3264F4F419744CF700E9E1B6 /* Frameworks */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | 3264F4F519744CF700E9E1B6 /* AppKit.framework */, 179 | 3264F4F719744CF700E9E1B6 /* Foundation.framework */, 180 | ); 181 | name = Frameworks; 182 | sourceTree = ""; 183 | }; 184 | 3264F4F919744CF700E9E1B6 /* XTrello */ = { 185 | isa = PBXGroup; 186 | children = ( 187 | 89F378AD1D827FF9008D36CF /* PureLayout */, 188 | 32979D111975991D0073F267 /* DataModel */, 189 | 322B729E19744FAB00555109 /* API */, 190 | 322B728119744F8900555109 /* Categories and Subclasses */, 191 | 322B729419744F9300555109 /* View Classes */, 192 | 3264F4FF19744CF700E9E1B6 /* XTrello.h */, 193 | 3264F50019744CF700E9E1B6 /* XTrello.m */, 194 | 32FEA90E1975D02B008B3661 /* XTrelloItem.h */, 195 | 32FEA90F1975D02B008B3661 /* XTrelloItem.m */, 196 | 322B727C19744E5700555109 /* XTWindowController.h */, 197 | 322B727D19744E5700555109 /* XTWindowController.m */, 198 | 322B727E19744E5700555109 /* XTWindowController.xib */, 199 | 3264F4FA19744CF700E9E1B6 /* Supporting Files */, 200 | ); 201 | path = XTrello; 202 | sourceTree = ""; 203 | }; 204 | 3264F4FA19744CF700E9E1B6 /* Supporting Files */ = { 205 | isa = PBXGroup; 206 | children = ( 207 | 3264F4FB19744CF700E9E1B6 /* XTrello-Info.plist */, 208 | 3264F4FC19744CF700E9E1B6 /* InfoPlist.strings */, 209 | 3264F50219744CF700E9E1B6 /* XTrello-Prefix.pch */, 210 | ); 211 | name = "Supporting Files"; 212 | sourceTree = ""; 213 | }; 214 | 32979D111975991D0073F267 /* DataModel */ = { 215 | isa = PBXGroup; 216 | children = ( 217 | 32CFDAA119749C050008F69A /* XTModel.h */, 218 | 32CFDAA219749C050008F69A /* XTModel.m */, 219 | 32CFDAA319749C050008F69A /* XTProjectSetting.h */, 220 | 32CFDAA419749C050008F69A /* XTProjectSetting.m */, 221 | ); 222 | name = DataModel; 223 | sourceTree = ""; 224 | }; 225 | 89F378AD1D827FF9008D36CF /* PureLayout */ = { 226 | isa = PBXGroup; 227 | children = ( 228 | 89F378AE1D827FF9008D36CF /* ALView+PureLayout.h */, 229 | 89F378AF1D827FF9008D36CF /* ALView+PureLayout.m */, 230 | 89F378B01D827FF9008D36CF /* NSArray+PureLayout.h */, 231 | 89F378B11D827FF9008D36CF /* NSArray+PureLayout.m */, 232 | 89F378B21D827FF9008D36CF /* NSLayoutConstraint+PureLayout.h */, 233 | 89F378B31D827FF9008D36CF /* NSLayoutConstraint+PureLayout.m */, 234 | 89F378B41D827FF9008D36CF /* PureLayout+Internal.h */, 235 | 89F378B51D827FF9008D36CF /* PureLayout.h */, 236 | 89F378B61D827FF9008D36CF /* PureLayoutDefines.h */, 237 | ); 238 | path = PureLayout; 239 | sourceTree = ""; 240 | }; 241 | /* End PBXGroup section */ 242 | 243 | /* Begin PBXNativeTarget section */ 244 | 3264F4F119744CF700E9E1B6 /* XTrello */ = { 245 | isa = PBXNativeTarget; 246 | buildConfigurationList = 3264F50519744CF700E9E1B6 /* Build configuration list for PBXNativeTarget "XTrello" */; 247 | buildPhases = ( 248 | 3264F4EE19744CF700E9E1B6 /* Sources */, 249 | 3264F4EF19744CF700E9E1B6 /* Frameworks */, 250 | 3264F4F019744CF700E9E1B6 /* Resources */, 251 | ); 252 | buildRules = ( 253 | ); 254 | dependencies = ( 255 | ); 256 | name = XTrello; 257 | productName = XTrello; 258 | productReference = 3264F4F219744CF700E9E1B6 /* XTrello.xcplugin */; 259 | productType = "com.apple.product-type.bundle"; 260 | }; 261 | /* End PBXNativeTarget section */ 262 | 263 | /* Begin PBXProject section */ 264 | 3264F4EA19744CF700E9E1B6 /* Project object */ = { 265 | isa = PBXProject; 266 | attributes = { 267 | LastUpgradeCheck = 0510; 268 | ORGANIZATIONNAME = "GlobalMed LLC"; 269 | }; 270 | buildConfigurationList = 3264F4ED19744CF700E9E1B6 /* Build configuration list for PBXProject "XTrello" */; 271 | compatibilityVersion = "Xcode 3.2"; 272 | developmentRegion = English; 273 | hasScannedForEncodings = 0; 274 | knownRegions = ( 275 | en, 276 | ); 277 | mainGroup = 3264F4E919744CF700E9E1B6; 278 | productRefGroup = 3264F4F319744CF700E9E1B6 /* Products */; 279 | projectDirPath = ""; 280 | projectRoot = ""; 281 | targets = ( 282 | 3264F4F119744CF700E9E1B6 /* XTrello */, 283 | ); 284 | }; 285 | /* End PBXProject section */ 286 | 287 | /* Begin PBXResourcesBuildPhase section */ 288 | 3264F4F019744CF700E9E1B6 /* Resources */ = { 289 | isa = PBXResourcesBuildPhase; 290 | buildActionMask = 2147483647; 291 | files = ( 292 | 3264F4FE19744CF700E9E1B6 /* InfoPlist.strings in Resources */, 293 | 322B728019744E5700555109 /* XTWindowController.xib in Resources */, 294 | ); 295 | runOnlyForDeploymentPostprocessing = 0; 296 | }; 297 | /* End PBXResourcesBuildPhase section */ 298 | 299 | /* Begin PBXSourcesBuildPhase section */ 300 | 3264F4EE19744CF700E9E1B6 /* Sources */ = { 301 | isa = PBXSourcesBuildPhase; 302 | buildActionMask = 2147483647; 303 | files = ( 304 | 322B729019744F8900555109 /* NSString+trelloAdditions.m in Sources */, 305 | 32FEA9101975D02B008B3661 /* XTrelloItem.m in Sources */, 306 | 322B728F19744F8900555109 /* NSDictionary+trelloAdditions.m in Sources */, 307 | 3264F50119744CF700E9E1B6 /* XTrello.m in Sources */, 308 | 89F378B81D827FF9008D36CF /* NSArray+PureLayout.m in Sources */, 309 | 89A7E8151DC330910047F32C /* NSMenuItem+boardDict.m in Sources */, 310 | 895236941A21539000719E09 /* NSColor+Hex.m in Sources */, 311 | 322B72A119744FAB00555109 /* XTTrelloWrapper.m in Sources */, 312 | 322B728E19744F8900555109 /* NSArray+trelloAdditions.m in Sources */, 313 | 322B729B19744F9300555109 /* XTTagView.m in Sources */, 314 | 322B729C19744F9300555109 /* XTTagViewController.m in Sources */, 315 | 322B727F19744E5700555109 /* XTWindowController.m in Sources */, 316 | 32CFDAA619749C050008F69A /* XTProjectSetting.m in Sources */, 317 | 32871C05197831FF00277DEB /* NSDate+trelloAdditions.m in Sources */, 318 | 32CFDAA519749C050008F69A /* XTModel.m in Sources */, 319 | 89F378B91D827FF9008D36CF /* NSLayoutConstraint+PureLayout.m in Sources */, 320 | 32CFDAA919749C560008F69A /* NSData+Split.m in Sources */, 321 | 322B729219744F8900555109 /* XTMenuItem.m in Sources */, 322 | 322B729119744F8900555109 /* NSView+trelloAdditions.m in Sources */, 323 | 89F378B71D827FF9008D36CF /* ALView+PureLayout.m in Sources */, 324 | 322B729319744F8900555109 /* XTTableView.m in Sources */, 325 | 322B729D19744F9300555109 /* XTTrelloCardView.m in Sources */, 326 | ); 327 | runOnlyForDeploymentPostprocessing = 0; 328 | }; 329 | /* End PBXSourcesBuildPhase section */ 330 | 331 | /* Begin PBXVariantGroup section */ 332 | 3264F4FC19744CF700E9E1B6 /* InfoPlist.strings */ = { 333 | isa = PBXVariantGroup; 334 | children = ( 335 | 3264F4FD19744CF700E9E1B6 /* en */, 336 | ); 337 | name = InfoPlist.strings; 338 | sourceTree = ""; 339 | }; 340 | /* End PBXVariantGroup section */ 341 | 342 | /* Begin XCBuildConfiguration section */ 343 | 3264F50319744CF700E9E1B6 /* Debug */ = { 344 | isa = XCBuildConfiguration; 345 | buildSettings = { 346 | ALWAYS_SEARCH_USER_PATHS = NO; 347 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 348 | CLANG_CXX_LIBRARY = "libc++"; 349 | CLANG_ENABLE_MODULES = YES; 350 | CLANG_ENABLE_OBJC_ARC = YES; 351 | CLANG_WARN_BOOL_CONVERSION = YES; 352 | CLANG_WARN_CONSTANT_CONVERSION = YES; 353 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 354 | CLANG_WARN_EMPTY_BODY = YES; 355 | CLANG_WARN_ENUM_CONVERSION = YES; 356 | CLANG_WARN_INT_CONVERSION = YES; 357 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 358 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 359 | COPY_PHASE_STRIP = NO; 360 | GCC_C_LANGUAGE_STANDARD = gnu99; 361 | GCC_DYNAMIC_NO_PIC = NO; 362 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 363 | GCC_OPTIMIZATION_LEVEL = 0; 364 | GCC_PREPROCESSOR_DEFINITIONS = ( 365 | "DEBUG=1", 366 | "$(inherited)", 367 | ); 368 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 369 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 370 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 371 | GCC_WARN_UNDECLARED_SELECTOR = YES; 372 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 373 | GCC_WARN_UNUSED_FUNCTION = YES; 374 | GCC_WARN_UNUSED_VARIABLE = YES; 375 | MACOSX_DEPLOYMENT_TARGET = 10.8; 376 | ONLY_ACTIVE_ARCH = YES; 377 | SDKROOT = macosx; 378 | }; 379 | name = Debug; 380 | }; 381 | 3264F50419744CF700E9E1B6 /* Release */ = { 382 | isa = XCBuildConfiguration; 383 | buildSettings = { 384 | ALWAYS_SEARCH_USER_PATHS = NO; 385 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 386 | CLANG_CXX_LIBRARY = "libc++"; 387 | CLANG_ENABLE_MODULES = YES; 388 | CLANG_ENABLE_OBJC_ARC = YES; 389 | CLANG_WARN_BOOL_CONVERSION = YES; 390 | CLANG_WARN_CONSTANT_CONVERSION = YES; 391 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 392 | CLANG_WARN_EMPTY_BODY = YES; 393 | CLANG_WARN_ENUM_CONVERSION = YES; 394 | CLANG_WARN_INT_CONVERSION = YES; 395 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 396 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 397 | COPY_PHASE_STRIP = YES; 398 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 399 | ENABLE_NS_ASSERTIONS = NO; 400 | GCC_C_LANGUAGE_STANDARD = gnu99; 401 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 402 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 403 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 404 | GCC_WARN_UNDECLARED_SELECTOR = YES; 405 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 406 | GCC_WARN_UNUSED_FUNCTION = YES; 407 | GCC_WARN_UNUSED_VARIABLE = YES; 408 | MACOSX_DEPLOYMENT_TARGET = 10.8; 409 | SDKROOT = macosx; 410 | }; 411 | name = Release; 412 | }; 413 | 3264F50619744CF700E9E1B6 /* Debug */ = { 414 | isa = XCBuildConfiguration; 415 | buildSettings = { 416 | CODE_SIGN_IDENTITY = ""; 417 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 418 | COMBINE_HIDPI_IMAGES = YES; 419 | DEPLOYMENT_LOCATION = YES; 420 | DSTROOT = "$(HOME)"; 421 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 422 | GCC_PREFIX_HEADER = "XTrello/XTrello-Prefix.pch"; 423 | INFOPLIST_FILE = "XTrello/XTrello-Info.plist"; 424 | INSTALL_PATH = "/Library/Application Support/Developer/Shared/Xcode/Plug-ins"; 425 | PRODUCT_NAME = "$(TARGET_NAME)"; 426 | PROVISIONING_PROFILE = ""; 427 | WRAPPER_EXTENSION = xcplugin; 428 | }; 429 | name = Debug; 430 | }; 431 | 3264F50719744CF700E9E1B6 /* Release */ = { 432 | isa = XCBuildConfiguration; 433 | buildSettings = { 434 | COMBINE_HIDPI_IMAGES = YES; 435 | DEPLOYMENT_LOCATION = YES; 436 | DSTROOT = "$(HOME)"; 437 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 438 | GCC_PREFIX_HEADER = "XTrello/XTrello-Prefix.pch"; 439 | INFOPLIST_FILE = "XTrello/XTrello-Info.plist"; 440 | INSTALL_PATH = "/Library/Application Support/Developer/Shared/Xcode/Plug-ins"; 441 | PRODUCT_NAME = "$(TARGET_NAME)"; 442 | WRAPPER_EXTENSION = xcplugin; 443 | }; 444 | name = Release; 445 | }; 446 | /* End XCBuildConfiguration section */ 447 | 448 | /* Begin XCConfigurationList section */ 449 | 3264F4ED19744CF700E9E1B6 /* Build configuration list for PBXProject "XTrello" */ = { 450 | isa = XCConfigurationList; 451 | buildConfigurations = ( 452 | 3264F50319744CF700E9E1B6 /* Debug */, 453 | 3264F50419744CF700E9E1B6 /* Release */, 454 | ); 455 | defaultConfigurationIsVisible = 0; 456 | defaultConfigurationName = Release; 457 | }; 458 | 3264F50519744CF700E9E1B6 /* Build configuration list for PBXNativeTarget "XTrello" */ = { 459 | isa = XCConfigurationList; 460 | buildConfigurations = ( 461 | 3264F50619744CF700E9E1B6 /* Debug */, 462 | 3264F50719744CF700E9E1B6 /* Release */, 463 | ); 464 | defaultConfigurationIsVisible = 0; 465 | defaultConfigurationName = Release; 466 | }; 467 | /* End XCConfigurationList section */ 468 | }; 469 | rootObject = 3264F4EA19744CF700E9E1B6 /* Project object */; 470 | } 471 | -------------------------------------------------------------------------------- /XTrello.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /XTrello/API/XTTrelloWrapper.h: -------------------------------------------------------------------------------- 1 | // 2 | // XTTrelloWrapper.h 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/10/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #define OUR_DATE_FORMAT @"MMddyy_HHmmss" 10 | #define NEW_DATE_FORMAT @"yyyy-MM-dd" 11 | #define HOUR_FORMAT @"HH:mm:SS" 12 | 13 | #import 14 | 15 | typedef NS_ENUM(NSInteger, XTInitialNoteType) { 16 | XTToDoType, 17 | XTBugsType, 18 | XTActiveType, 19 | XTBlockedType, 20 | XTDoneType, 21 | XTBacklogType, 22 | }; 23 | 24 | static NSString *const TImprovementLabel = @"improvment"; 25 | static NSString *const TInvestigationLabel = @"investigation"; 26 | static NSString *const TToolLabel = @"tool"; 27 | static NSString *const TBugLabel = @"bug"; 28 | static NSString *const TTestingLabel = @"testing"; 29 | static NSString *const TFeatureLabel = @"feature"; 30 | 31 | @protocol XTTrelloWrapperProtocol; 32 | 33 | @interface XTTrelloWrapper : NSObject 34 | { 35 | NSDate *startDate; 36 | } 37 | @property (readwrite, assign) BOOL dataReady; 38 | @property (readwrite, assign) BOOL reloading; 39 | @property (nonatomic, strong) NSString *sessionToken; 40 | @property (nonatomic, strong) NSString *baseURL; 41 | @property (nonatomic, strong) NSString *apiKey; 42 | @property (atomic, strong) NSMutableDictionary *trelloData; 43 | @property (nonatomic, weak) id delegate; 44 | 45 | + (id)sharedInstance; 46 | 47 | - (NSDictionary *)moveCard:(NSDictionary *)theCard toBoardNamed:(NSString *)boardName; 48 | 49 | - (NSDictionary *)moveCard:(NSDictionary *)theCard fromBoardNamed:(NSString *)oldBoardName toBoardNamed:(NSString *)boardName toListNamed:(NSString *)listName; 50 | 51 | + (NSString *)UTCDateFromDate:(NSDate *)theDate; 52 | - (NSDictionary *)addCardToBoard:(NSString *)boardName inList:(NSString *)listName withName:(NSString *)cardName withDescription:(NSString *)theDescription; 53 | - (NSArray *)closedCardsInBoard:(NSString *)boardName; 54 | - (NSDictionary *)deleteCard:(NSDictionary *)theCard inBoardNamed:(NSString *)boardName; 55 | - (NSDictionary *)addMemberId:(NSString *)memberID toCard:(NSDictionary *)theCard inBoardNamed:(NSString *)boardName; 56 | - (NSDictionary *)removeMemberId:(NSString *)memberID fromCard:(NSDictionary *)theCard inBoardNamed:(NSString *)boardName; 57 | - (NSDictionary *)moveCard:(NSDictionary *)theCard toListWithID:(NSString *)listID inBoardNamed:(NSString *)boardName; 58 | - (NSDictionary *)addCardToBoard:(NSString *)boardName inList:(NSString *)listName withName:(NSString *)cardName; 59 | - (NSDictionary *)addCardToBoard:(NSString *)boardName inList:(NSString *)listName withName:(NSString *)cardName inPosition:(NSString *)thePosition; 60 | - (NSString *)initialNoteForType:(XTInitialNoteType)noteType; 61 | - (void)closeBoardWithName:(NSString *)boardName; 62 | - (void)closeListWithName:(NSString *)theList inBoardNamed:(NSString *)boardName; 63 | - (void)closeBoardWithID:(NSString *)boardID; 64 | - (void)closeListWithID:(NSString *)listID; 65 | - (NSDictionary *)updateLocalCard:(NSDictionary *)theCard withName:(NSString *)theName inBoardNamed:(NSString *)boardName; 66 | - (NSDictionary *)updateLocalCardLabels:(NSDictionary *)theCard withList:(NSArray *)theList inBoardNamed:(NSString *)boardName; 67 | 68 | - (void)setDueDate:(NSString *)dueDate forCardWithName:(NSString *)cardName inBoardNamed:(NSString *)boardName; 69 | - (void)setDueDate:(NSString *)dueDate forCardWithID:(NSString *)theCard; 70 | 71 | - (void)setDefaultLabelsForBoardNamed:(NSString *)boardName; 72 | - (void)moveCardNamed:(NSString *)cardName inBoardNamed:(NSString *)boardName toPosition:(NSString *)newPosition; 73 | 74 | - (void)setLabelName:(NSString *)labelName forColor:(NSString *)colorName inBoardWithID:(NSString *)boardID; 75 | - (void)addMemberNamed:(NSString *)memberName toCardWithName:(NSString *)cardName inBoardNamed:(NSString *)boardName; 76 | - (void)addMemberID:(NSString *)memberID toCardWithID:(NSString *)cardID; 77 | - (void)deleteCardWithID:(NSString *)cardID; 78 | - (void)removeMemberNamed:(NSString *)memberName fromCardNamed:(NSString *)cardName inBoard:(NSString *)boardName; 79 | - (void)removeMemberWithID:(NSString *)memberID fromCardID:(NSString *)cardID; 80 | - (NSArray *)cardCommentsFromCardNamed:(NSString *)cardName inBoard:(NSString *)boardName; 81 | - (NSArray *)cardCommentsFromCardID:(NSString *)cardID; 82 | - (void)postComment:(NSString *)theComment toCardNamed:(NSString *)cardName inBoardNamed:(NSString *)boardName; 83 | 84 | - (void)postComment:(NSString *)theComment toCardWithID:(NSString *)cardID; 85 | - (void)moveCardNamed:(NSString *)cardName toListWithName:(NSString *)listName inBoardNamed:(NSString *)boardName; 86 | - (void)moveCardWithID:(NSString *)cardID toListWithID:(NSString *)theList; 87 | - (NSDictionary *)createCardWithName:(NSString *)cardName toListWithName:(NSString *)listName inBoardNamed:(NSString *)boardName; 88 | - (NSDictionary *)createCardWithName:(NSString *)cardName toListWithID:(NSString *)listID; 89 | - (void)setDescription:(NSString *)theDesc forCardNamed:(NSString *)cardName inBoardNamed:(NSString *)boardName; 90 | - (void)setDescription:(NSString *)theDesc forCardWithID:(NSString *)theCard; 91 | 92 | - (void)deleteLabelID:(NSString *)labelID forCardWithID:(NSString *)theCard; 93 | - (void)addLabelID:(NSString *)labelsString forCardWithID:(NSString *)theCard; 94 | - (void)setLabels:(NSArray *)theLabels forCardNamed:(NSString *)cardName inBoardNamed:(NSString *)boardName; 95 | - (void)setLabels:(NSArray *)theLabels forCardWithID:(NSString *)theCard; 96 | - (NSDictionary *)labelDictionaryFromColor:(NSString *)colorName inBoardNamed:(NSString *)boardName; 97 | 98 | - (void)changeListName:(NSString *)theList toName:(NSString *)listName inBoardNamed:(NSString *)boardName; 99 | - (void)changeListWithID:(NSString *)listID toName:(NSString *)listName; 100 | - (void)changeListWithID:(NSString *)listID toPosition:(NSString *)newPosition; 101 | - (void)changeListNamed:(NSString *)theListName inBoard:(NSString *)boardName toPosition:(NSString *)newPosition; 102 | - (void)createListWithName:(NSString *)listName inBoardWithID:(NSString *)boardID inLocation:(NSString *)location; 103 | - (void)createListWithName:(NSString *)listName inBoardNamed:(NSString *)boardName; 104 | - (void)createListWithName:(NSString *)listName inBoardNamed:(NSString *)boardName inLocation:(NSString *)location; 105 | - (NSDictionary *)createBoardWithName:(NSString *)boardName inOrganization:(NSString *)orgName; 106 | - (NSDictionary *)organizationWithNameOrID:(NSString *)organizationName; 107 | - (void)changeBoard:(NSString *)boardName toOrganizationWithNameOrID:(NSString *)organizationName; 108 | - (NSDictionary *)performSynchronousConnectionFromURLRequest:(NSMutableURLRequest *)request; 109 | - (void)createNewTemplateBoardWithName:(NSString *)boardName inOrganization:(NSString *)orgName; 110 | - (void)reloadTrelloData; 111 | - (void)fetchTrelloData; 112 | - (void)loadPreviousData; 113 | - (NSString *)firstOrganizationName; 114 | - (NSDictionary *)cardWithName:(NSString *)cardName inBoardNamed:(NSString *)boardName; 115 | - (NSDictionary *)listWithName:(NSString *)listName inBoardNamed:(NSString *)boardName; 116 | - (NSArray *)cardsFromListWithName:(NSString *)listName inBoard:(NSString *)boardName; 117 | - (NSDictionary *)boardNamed:(NSString *)boardName; 118 | @end 119 | 120 | @protocol XTTrelloWrapperProtocol 121 | 122 | - (void)trelloDataFetched:(NSDictionary *)theData; 123 | - (void)trelloDataUpdated:(NSDictionary *)theData; 124 | - (void)setInitialData:(NSDictionary *)theData; 125 | @end -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/NSArray+trelloAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+trelloAdditions.h 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/12/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSArray (trelloAdditions) 12 | - (NSString *)labelString; 13 | - (BOOL)containsString:(NSString *)theString; //will check to see if any object in the array contains 14 | //even part of a string; 15 | @end 16 | -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/NSArray+trelloAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+trelloAdditions.m 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/12/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import "NSArray+trelloAdditions.h" 10 | 11 | @implementation NSArray (trelloAdditions) 12 | 13 | - (NSString *)labelString; 14 | { 15 | NSMutableArray *newArray = [NSMutableArray new]; 16 | NSString *returnString = nil; 17 | for (NSDictionary *currentColor in self) 18 | { 19 | if (![currentColor respondsToSelector:@selector(allKeys)])return nil; 20 | 21 | //[newArray addObject:[currentColor key]]; 22 | 23 | } 24 | 25 | if ([newArray count] > 0) 26 | { 27 | returnString = [newArray componentsJoinedByString:@","]; 28 | } 29 | 30 | return returnString; 31 | } 32 | 33 | - (BOOL)containsString:(NSString *)theString 34 | { 35 | NSInteger idx = [self indexOfObjectPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 36 | 37 | if ([obj rangeOfString:theString].location != NSNotFound) 38 | { 39 | return YES; 40 | } else { 41 | return NO; 42 | } 43 | 44 | }]; 45 | 46 | if (idx == NSNotFound) return NO; 47 | 48 | return YES; 49 | 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/NSColor+Hex.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSColor+Hex.h 3 | // EncounterConnect 4 | // 5 | // Created by Kevin Bradley on 9/19/13. 6 | // Copyright (c) 2013 nito. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSColor (Hex) 12 | + (NSColor *)pinkColor; 13 | + (NSColor *)limeColor; 14 | + (NSColor *)skyColor; 15 | + (NSColor *)lightBlueAlternate; 16 | + (NSColor *)lightBlueColor; 17 | + (NSColor *)colorFromHex:(NSString *)s; 18 | - (NSString *)hexValue; 19 | + (NSColor *)sourceListLightColor; 20 | @end 21 | -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/NSColor+Hex.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSColor+Hex.m 3 | // EncounterConnect 4 | // 5 | // Created by Kevin Bradley on 9/19/13. 6 | // Copyright (c) 2013 nito. All rights reserved. 7 | // 8 | 9 | #import "NSColor+Hex.h" 10 | 11 | @implementation NSColor (Hex) 12 | 13 | + (NSColor *)pinkColor 14 | { 15 | return [NSColor colorFromHex:@"ff69b4"]; 16 | } 17 | 18 | + (NSColor *)skyColor 19 | { 20 | return [NSColor colorFromHex:@"87CEEB"]; 21 | } 22 | 23 | + (NSColor *)limeColor 24 | { 25 | return [NSColor colorFromHex:@"32CD32"]; 26 | } 27 | 28 | + (NSColor *)lightBlueAlternate 29 | { 30 | return [NSColor colorFromHex:@"149CEA"]; 31 | } 32 | 33 | +(NSColor *)lightBlueColor 34 | { 35 | return [NSColor colorFromHex:@"89bce9"]; 36 | } 37 | 38 | + (NSColor *)colorFromHex:(NSString *)s 39 | { 40 | NSScanner *scan = [NSScanner scannerWithString:[s substringToIndex:2]]; 41 | unsigned int r = 0, g = 0, b = 0; 42 | [scan scanHexInt:&r]; 43 | scan = [NSScanner scannerWithString:[[s substringFromIndex:2] substringToIndex:2]]; 44 | [scan scanHexInt:&g]; 45 | scan = [NSScanner scannerWithString:[s substringFromIndex:4]]; 46 | [scan scanHexInt:&b]; 47 | 48 | 49 | return [NSColor colorWithCalibratedRed:(float)r/255.0 green:(float)g/255.0 blue:(float)b/255.0 alpha:1.0]; 50 | } 51 | 52 | - (NSString *)hexValue 53 | { 54 | CGFloat red, green, blue; 55 | [[self colorUsingColorSpaceName: NSCalibratedRGBColorSpace] 56 | getRed: &red green: &green blue: &blue alpha: nil]; 57 | 58 | NSString *occs = [NSString stringWithFormat: @"%02X%02X%02X", (unsigned)(red*255.0), 59 | (unsigned)(green*255.0), (unsigned)(blue*255.0)]; 60 | 61 | 62 | return occs; 63 | } 64 | 65 | + (NSColor *)sourceListLightColor 66 | { 67 | return [NSColor colorWithCatalogName:@"System" colorName:@"_sourceListBackgroundColor"]; 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/NSDate+trelloAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDate+trelloAdditions.h 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/17/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSDate (trelloAdditions) 12 | - (NSString *)timeStringFromCurrentDate; 13 | @end 14 | -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/NSDate+trelloAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDate+trelloAdditions.m 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/17/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import "NSDate+trelloAdditions.h" 10 | 11 | @implementation NSDate (trelloAdditions) 12 | 13 | - (NSString *)timeStringFromCurrentDate 14 | { 15 | NSDate *currentDate = [NSDate date]; 16 | NSTimeInterval timeInt = [currentDate timeIntervalSinceDate:self]; 17 | // NSLog(@"timeInt: %f", timeInt); 18 | NSInteger minutes = floor(timeInt/60); 19 | NSInteger seconds = round(timeInt - minutes * 60); 20 | return [NSString stringWithFormat:@"%ld:%02ld", (long)minutes, (long)seconds]; 21 | 22 | } 23 | 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/NSDictionary+trelloAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDictionary+trelloAdditions.h 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/10/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSDictionary (trelloAdditions) 12 | - (NSDictionary *)dictionaryByReplacingNullsWithStrings; 13 | - (NSString *)stringRepresentation; 14 | @end 15 | -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/NSDictionary+trelloAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDictionary+trelloAdditions.m 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/10/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import "NSDictionary+trelloAdditions.h" 10 | 11 | @implementation NSDictionary (trelloAdditions) 12 | 13 | 14 | - (NSString *)stringRepresentation 15 | { 16 | NSString *error = nil; 17 | NSData *xmlData = [NSPropertyListSerialization dataFromPropertyList:self format:NSPropertyListXMLFormat_v1_0 errorDescription:&error]; 18 | NSString *s=[[NSString alloc] initWithData:xmlData encoding: NSUTF8StringEncoding]; 19 | return s; 20 | } 21 | 22 | 23 | - (NSDictionary *)dictionaryByReplacingNullsWithStrings { 24 | const NSMutableDictionary *replaced = [self mutableCopy]; 25 | const id nul = [NSNull null]; 26 | const NSString *blank = @""; 27 | 28 | for(NSString *key in self) { 29 | const id object = [self objectForKey:key]; 30 | if(object == nul) { 31 | //pointer comparison is way faster than -isKindOfClass: 32 | //since [NSNull null] is a singleton, they'll all point to the same 33 | //location in memory. 34 | [replaced setObject:blank 35 | forKey:key]; 36 | } 37 | if ([object respondsToSelector:@selector(allKeys)]) 38 | { 39 | id newObject = [object dictionaryByReplacingNullsWithStrings]; 40 | [replaced setObject:newObject forKey:key]; 41 | } 42 | } 43 | 44 | return [replaced copy]; 45 | } 46 | 47 | @end -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/NSMenuItem+boardDict.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSMenuItem+boardDict.h 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 10/28/16. 6 | // Copyright © 2016 GlobalMed LLC. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface NSObject (AMAssociatedObjects) 13 | - (void)associateValue:(id)value withKey:(void *)key; // Strong reference 14 | - (void)weaklyAssociateValue:(id)value withKey:(void *)key; 15 | - (id)associatedValueForKey:(void *)key; 16 | 17 | @end 18 | 19 | 20 | @interface NSMenuItem (boardDict) 21 | 22 | @property (nonatomic) NSDictionary *boardDictionary; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/NSMenuItem+boardDict.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSMenuItem+boardDict.m 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 10/28/16. 6 | // Copyright © 2016 GlobalMed LLC. All rights reserved. 7 | // 8 | 9 | #import "NSMenuItem+boardDict.h" 10 | 11 | @implementation NSObject (AMAssociatedObjects) 12 | 13 | 14 | - (void)associateValue:(id)value withKey:(void *)key 15 | { 16 | objc_setAssociatedObject(self, key, value, OBJC_ASSOCIATION_RETAIN); 17 | } 18 | 19 | - (void)weaklyAssociateValue:(id)value withKey:(void *)key 20 | { 21 | objc_setAssociatedObject(self, key, value, OBJC_ASSOCIATION_ASSIGN); 22 | } 23 | 24 | - (id)associatedValueForKey:(void *)key 25 | { 26 | return objc_getAssociatedObject(self, key); 27 | } 28 | 29 | @end 30 | 31 | 32 | @implementation NSMenuItem (boardDict) 33 | 34 | - (NSDictionary *)boardDictionary 35 | { 36 | return [self associatedValueForKey:@selector(boardDictionary)]; 37 | } 38 | 39 | - (void)setBoardDictionary:(NSDictionary *)boardDictionary 40 | { 41 | [self associateValue:boardDictionary withKey:@selector(boardDictionary)]; 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/NSString+trelloAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+trelloAdditions.h 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/10/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | @interface NSString (trelloAdditions) 12 | 13 | - (CGFloat)heightForStringWithFont:(NSFont *)myFont withWidth:(CGFloat)myWidth; 14 | - (NSDictionary *)dictionaryRepresentation; 15 | - (NSColor *)colorFromName; 16 | - (NSString *)tildePath; 17 | @end 18 | -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/NSString+trelloAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+trelloAdditions.m 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/10/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import "NSString+trelloAdditions.h" 10 | 11 | @implementation NSString (trelloAdditions) 12 | 13 | - (NSString *)tildePath 14 | { 15 | NSArray *pathComponents = [self componentsSeparatedByString:@"/"]; 16 | NSArray *newPath = [pathComponents subarrayWithRange:NSMakeRange(3, pathComponents.count - 3)]; 17 | return [NSString stringWithFormat:@"~/%@", [newPath componentsJoinedByString:@"/"]]; 18 | } 19 | 20 | 21 | - (CGFloat)heightForStringWithFont:(NSFont *)myFont withWidth:(CGFloat)myWidth 22 | { 23 | NSTextStorage *textStorage = [[NSTextStorage alloc] initWithString:self]; 24 | NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize:NSMakeSize(myWidth, FLT_MAX)]; 25 | ; 26 | NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init]; 27 | [layoutManager addTextContainer:textContainer]; 28 | [textStorage addLayoutManager:layoutManager]; 29 | [textStorage addAttribute:NSFontAttributeName value:myFont 30 | range:NSMakeRange(0, [textStorage length])]; 31 | [textContainer setLineFragmentPadding:0.0]; 32 | 33 | (void) [layoutManager glyphRangeForTextContainer:textContainer]; 34 | return [layoutManager 35 | usedRectForTextContainer:textContainer].size.height; 36 | } 37 | 38 | 39 | - (NSDictionary *)dictionaryRepresentation 40 | { 41 | NSString *error = nil; 42 | NSPropertyListFormat format; 43 | NSData *theData = [self dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES]; 44 | id theDict = [NSPropertyListSerialization propertyListFromData:theData 45 | mutabilityOption:NSPropertyListImmutable 46 | format:&format 47 | errorDescription:&error]; 48 | return theDict; 49 | } 50 | 51 | // return [NSArray arrayWithObjects:@"blue", @"green", @"orange", @"purple", @"red", @"yellow", nil]; 52 | 53 | /* 54 | 55 | 11/22/14 4:23:46.475 PM Xcode[54035]: ### labelArray: { 56 | black = ""; 57 | blue = ""; 58 | green = ""; 59 | lime = ""; 60 | orange = ""; 61 | pink = ""; 62 | purple = ""; 63 | red = ""; 64 | sky = ""; 65 | yellow = ""; 66 | } 67 | 68 | 69 | */ 70 | 71 | - (NSColor *)colorFromName 72 | { 73 | // NSLog(@"### name: %@", self); 74 | if ([[self lowercaseString] isEqualToString:@"black"]) return [NSColor blackColor]; 75 | if ([[self lowercaseString] isEqualToString:@"blue"]) return [NSColor blueColor]; 76 | if ([[self lowercaseString] isEqualToString:@"green"]) return [NSColor greenColor]; 77 | if ([[self lowercaseString] isEqualToString:@"lime"]) return [NSColor limeColor]; 78 | if ([[self lowercaseString] isEqualToString:@"orange"]) return [NSColor orangeColor]; 79 | if ([[self lowercaseString] isEqualToString:@"pink"]) return [NSColor pinkColor]; 80 | if ([[self lowercaseString] isEqualToString:@"purple"]) return [NSColor purpleColor]; 81 | if ([[self lowercaseString] isEqualToString:@"red"]) return [NSColor redColor]; 82 | if ([[self lowercaseString] isEqualToString:@"sky"]) return [NSColor skyColor]; 83 | if ([[self lowercaseString] isEqualToString:@"yellow"]) return [NSColor yellowColor]; 84 | 85 | return nil; 86 | } 87 | 88 | @end -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/NSView+trelloAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSView+trelloAdditions.h 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/11/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSView (trelloAdditions) 12 | 13 | - (void)insertSubview:(NSView *)theView atIndex:(NSInteger)index; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/NSView+trelloAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSView+trelloAdditions.m 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/11/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import "NSView+trelloAdditions.h" 10 | 11 | @implementation NSView (trelloAdditions) 12 | 13 | - (void)insertSubview:(NSView *)theView atIndex:(NSInteger)index 14 | { 15 | NSMutableArray *mutableSubviews = [[self subviews] mutableCopy]; 16 | [mutableSubviews insertObject:theView atIndex:index]; 17 | [self setSubviews:mutableSubviews]; 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/XTMenuItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // XTMenuItem.h 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/12/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface XTMenuItem : NSMenuItem 12 | 13 | @property (nonatomic, strong) NSString *realValue; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/XTMenuItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // XTMenuItem.m 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/12/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import "XTMenuItem.h" 10 | 11 | @implementation XTMenuItem 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/XTTableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // XTTableView.h 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/11/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "XTTrelloCardView.h" 11 | 12 | @interface XTTableView : NSTableView 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /XTrello/Categories and Subclasses/XTTableView.m: -------------------------------------------------------------------------------- 1 | // 2 | // XTTableView.m 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/11/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import "XTTableView.h" 10 | 11 | @implementation XTTableView 12 | 13 | - (id)initWithFrame:(NSRect)frame 14 | { 15 | self = [super initWithFrame:frame]; 16 | if (self) { 17 | // Initialization code here. 18 | } 19 | return self; 20 | } 21 | 22 | -(void)mouseDown:(NSEvent *)theEvent { 23 | [super mouseDown:theEvent]; 24 | 25 | // Forward the click to the row's cell view 26 | NSPoint selfPoint = [self convertPoint:theEvent.locationInWindow fromView:nil]; 27 | NSInteger row = [self rowAtPoint:selfPoint]; 28 | if (row>=0) [(XTTrelloCardView *)[self viewAtColumn:0 row:row makeIfNecessary:NO] 29 | mouseDownForTextFields:theEvent]; 30 | } 31 | 32 | //- (void)drawRect:(NSRect)dirtyRect 33 | //{ 34 | // [super drawRect:dirtyRect]; 35 | // 36 | // // Drawing code here. 37 | //} 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /XTrello/NSData+Split.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+Split.h 3 | // 4 | // Created by ████ 5 | // 6 | 7 | #import 8 | 9 | 10 | /// An NSData category that allows splitting the data into separate components. 11 | 12 | @interface NSData (Split) 13 | 14 | /** Splits the source data into any array of components separated by the specified byte. 15 | 16 | Taken from http://www.geektheory.ca/blog/splitting-nsdata-object-data-specific-byte/ 17 | 18 | @param sep Byte to separate by. 19 | @return NSArray of components 20 | */ 21 | -(NSArray *)componentsSeparatedByByte:(Byte)sep; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /XTrello/NSData+Split.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+Split.m 3 | // 4 | // Created by ████ 5 | // 6 | 7 | #import "NSData+Split.h" 8 | 9 | @implementation NSData (Split) 10 | 11 | -(NSArray *)componentsSeparatedByByte:(Byte)sep; 12 | { 13 | unsigned long len, index, last_sep_index; 14 | NSData *line; 15 | NSMutableArray *lines = nil; 16 | 17 | len = [self length]; 18 | Byte *cData = malloc(len); 19 | if (cData == NULL) 20 | { 21 | return lines; 22 | } 23 | 24 | [self getBytes:cData length:len]; 25 | 26 | index = last_sep_index = 0; 27 | 28 | lines = [[NSMutableArray alloc] init]; 29 | 30 | do 31 | { 32 | if (sep == cData[index]) 33 | { 34 | NSRange startEndRange = NSMakeRange(last_sep_index, index - last_sep_index); 35 | line = [self subdataWithRange:startEndRange]; 36 | 37 | [lines addObject:line]; 38 | 39 | last_sep_index = index + 1; 40 | 41 | continue; 42 | } 43 | } while (index++ < len); 44 | 45 | free(cData); 46 | cData = NULL; 47 | 48 | return lines; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /XTrello/PureLayout/ALView+PureLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // ALView+PureLayout.h 3 | // https://github.com/PureLayout/PureLayout 4 | // 5 | // Copyright (c) 2012 Richard Turton 6 | // Copyright (c) 2013-2015 Tyler Fox 7 | // 8 | // This code is distributed under the terms and conditions of the MIT license. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to 12 | // deal in the Software without restriction, including without limitation the 13 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 14 | // sell copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in 18 | // all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 26 | // IN THE SOFTWARE. 27 | // 28 | 29 | #import "PureLayoutDefines.h" 30 | 31 | 32 | __PL_ASSUME_NONNULL_BEGIN 33 | 34 | #pragma mark ALView+PureLayout 35 | 36 | /** 37 | A category on UIView/NSView that provides a simple yet powerful interface for creating Auto Layout constraints. 38 | */ 39 | @interface ALView (PureLayout) 40 | 41 | 42 | #pragma mark Factory & Initializer Methods 43 | 44 | /** Creates and returns a new view that does not convert the autoresizing mask into constraints. */ 45 | + (instancetype)newAutoLayoutView; 46 | 47 | /** Initializes and returns a new view that does not convert the autoresizing mask into constraints. */ 48 | - (instancetype)initForAutoLayout; 49 | 50 | /** Configures an existing view to not convert the autoresizing mask into constraints and returns the view. */ 51 | - (instancetype)configureForAutoLayout; 52 | 53 | 54 | #pragma mark Center & Align in Superview 55 | 56 | /** Centers the view in its superview. */ 57 | - (__NSArray_of(NSLayoutConstraint *) *)autoCenterInSuperview; 58 | 59 | /** Aligns the view to the same axis of its superview. */ 60 | - (NSLayoutConstraint *)autoAlignAxisToSuperviewAxis:(ALAxis)axis; 61 | 62 | #if __PureLayout_MinBaseSDK_iOS_8_0 63 | 64 | /** Centers the view in its superview's margins. Available in iOS 8.0 and later. */ 65 | - (__NSArray_of(NSLayoutConstraint *) *)autoCenterInSuperviewMargins; 66 | 67 | /** Aligns the view to the corresponding margin axis of its superview. Available in iOS 8.0 and later. */ 68 | - (NSLayoutConstraint *)autoAlignAxisToSuperviewMarginAxis:(ALAxis)axis; 69 | 70 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 */ 71 | 72 | 73 | #pragma mark Pin Edges to Superview 74 | 75 | /** Pins the given edge of the view to the same edge of its superview. */ 76 | - (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge; 77 | 78 | /** Pins the given edge of the view to the same edge of its superview with an inset. */ 79 | - (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge withInset:(CGFloat)inset; 80 | 81 | /** Pins the given edge of the view to the same edge of its superview with an inset as a maximum or minimum. */ 82 | - (NSLayoutConstraint *)autoPinEdgeToSuperviewEdge:(ALEdge)edge withInset:(CGFloat)inset relation:(NSLayoutRelation)relation; 83 | 84 | /** Pins the edges of the view to the edges of its superview. */ 85 | - (__NSArray_of(NSLayoutConstraint *) *)autoPinEdgesToSuperviewEdges; 86 | 87 | /** Pins the edges of the view to the edges of its superview with the given edge insets. */ 88 | - (__NSArray_of(NSLayoutConstraint *) *)autoPinEdgesToSuperviewEdgesWithInsets:(ALEdgeInsets)insets; 89 | 90 | /** Pins 3 of the 4 edges of the view to the edges of its superview with the given edge insets, excluding one edge. */ 91 | - (__NSArray_of(NSLayoutConstraint *) *)autoPinEdgesToSuperviewEdgesWithInsets:(ALEdgeInsets)insets excludingEdge:(ALEdge)edge; 92 | 93 | #if __PureLayout_MinBaseSDK_iOS_8_0 94 | 95 | /** Pins the given edge of the view to the corresponding margin of its superview. Available in iOS 8.0 and later. */ 96 | - (NSLayoutConstraint *)autoPinEdgeToSuperviewMargin:(ALEdge)edge; 97 | 98 | /** Pins the given edge of the view to the corresponding margin of its superview as a maximum or minimum. Available in iOS 8.0 and later. */ 99 | - (NSLayoutConstraint *)autoPinEdgeToSuperviewMargin:(ALEdge)edge relation:(NSLayoutRelation)relation; 100 | 101 | /** Pins the edges of the view to the margins of its superview. Available in iOS 8.0 and later. */ 102 | - (__NSArray_of(NSLayoutConstraint *) *)autoPinEdgesToSuperviewMargins; 103 | 104 | /** Pins 3 of the 4 edges of the view to the margins of its superview excluding one edge. Available in iOS 8.0 and later. */ 105 | - (__NSArray_of(NSLayoutConstraint *) *)autoPinEdgesToSuperviewMarginsExcludingEdge:(ALEdge)edge; 106 | 107 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 */ 108 | 109 | 110 | #pragma mark Pin Edges 111 | 112 | /** Pins an edge of the view to a given edge of another view. */ 113 | - (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)otherView; 114 | 115 | /** Pins an edge of the view to a given edge of another view with an offset. */ 116 | - (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)otherView withOffset:(CGFloat)offset; 117 | 118 | /** Pins an edge of the view to a given edge of another view with an offset as a maximum or minimum. */ 119 | - (NSLayoutConstraint *)autoPinEdge:(ALEdge)edge toEdge:(ALEdge)toEdge ofView:(ALView *)otherView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation; 120 | 121 | 122 | #pragma mark Align Axes 123 | 124 | /** Aligns an axis of the view to the same axis of another view. */ 125 | - (NSLayoutConstraint *)autoAlignAxis:(ALAxis)axis toSameAxisOfView:(ALView *)otherView; 126 | 127 | /** Aligns an axis of the view to the same axis of another view with an offset. */ 128 | - (NSLayoutConstraint *)autoAlignAxis:(ALAxis)axis toSameAxisOfView:(ALView *)otherView withOffset:(CGFloat)offset; 129 | 130 | /** Aligns an axis of the view to the same axis of another view with a multiplier. */ 131 | - (NSLayoutConstraint *)autoAlignAxis:(ALAxis)axis toSameAxisOfView:(ALView *)otherView withMultiplier:(CGFloat)multiplier; 132 | 133 | 134 | #pragma mark Match Dimensions 135 | 136 | /** Matches a dimension of the view to a given dimension of another view. */ 137 | - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView; 138 | 139 | /** Matches a dimension of the view to a given dimension of another view with an offset. */ 140 | - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView withOffset:(CGFloat)offset; 141 | 142 | /** Matches a dimension of the view to a given dimension of another view with an offset as a maximum or minimum. */ 143 | - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation; 144 | 145 | /** Matches a dimension of the view to a multiple of a given dimension of another view. */ 146 | - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView withMultiplier:(CGFloat)multiplier; 147 | 148 | /** Matches a dimension of the view to a multiple of a given dimension of another view as a maximum or minimum. */ 149 | - (NSLayoutConstraint *)autoMatchDimension:(ALDimension)dimension toDimension:(ALDimension)toDimension ofView:(ALView *)otherView withMultiplier:(CGFloat)multiplier relation:(NSLayoutRelation)relation; 150 | 151 | 152 | #pragma mark Set Dimensions 153 | 154 | /** Sets the view to a specific size. */ 155 | - (__NSArray_of(NSLayoutConstraint *) *)autoSetDimensionsToSize:(CGSize)size; 156 | 157 | /** Sets the given dimension of the view to a specific size. */ 158 | - (NSLayoutConstraint *)autoSetDimension:(ALDimension)dimension toSize:(CGFloat)size; 159 | 160 | /** Sets the given dimension of the view to a specific size as a maximum or minimum. */ 161 | - (NSLayoutConstraint *)autoSetDimension:(ALDimension)dimension toSize:(CGFloat)size relation:(NSLayoutRelation)relation; 162 | 163 | 164 | #pragma mark Set Content Compression Resistance & Hugging 165 | 166 | /** Sets the priority of content compression resistance for an axis. 167 | NOTE: This method must be called from within the block passed into the method +[NSLayoutConstraint autoSetPriority:forConstraints:] */ 168 | - (void)autoSetContentCompressionResistancePriorityForAxis:(ALAxis)axis; 169 | 170 | /** Sets the priority of content hugging for an axis. 171 | NOTE: This method must be called from within the block passed into the method +[NSLayoutConstraint autoSetPriority:forConstraints:] */ 172 | - (void)autoSetContentHuggingPriorityForAxis:(ALAxis)axis; 173 | 174 | 175 | #pragma mark Constrain Any Attributes 176 | 177 | /** Constrains an attribute of the view to a given attribute of another view. */ 178 | - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView; 179 | 180 | /** Constrains an attribute of the view to a given attribute of another view with an offset. */ 181 | - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView withOffset:(CGFloat)offset; 182 | 183 | /** Constrains an attribute of the view to a given attribute of another view with an offset as a maximum or minimum. */ 184 | - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView withOffset:(CGFloat)offset relation:(NSLayoutRelation)relation; 185 | 186 | /** Constrains an attribute of the view to a given attribute of another view with a multiplier. */ 187 | - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView withMultiplier:(CGFloat)multiplier; 188 | 189 | /** Constrains an attribute of the view to a given attribute of another view with a multiplier as a maximum or minimum. */ 190 | - (NSLayoutConstraint *)autoConstrainAttribute:(ALAttribute)attribute toAttribute:(ALAttribute)toAttribute ofView:(ALView *)otherView withMultiplier:(CGFloat)multiplier relation:(NSLayoutRelation)relation; 191 | 192 | 193 | #pragma mark Pin to Layout Guides (iOS only) 194 | 195 | #if TARGET_OS_IPHONE 196 | 197 | /** Pins the top edge of the view to the top layout guide of the given view controller with an inset. Available on iOS only. */ 198 | - (NSLayoutConstraint *)autoPinToTopLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset; 199 | 200 | /** Pins the top edge of the view to the top layout guide of the given view controller with an inset as a maximum or minimum. Available on iOS only. */ 201 | - (NSLayoutConstraint *)autoPinToTopLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset relation:(NSLayoutRelation)relation; 202 | 203 | /** Pins the bottom edge of the view to the bottom layout guide of the given view controller with an inset. Available on iOS only. */ 204 | - (NSLayoutConstraint *)autoPinToBottomLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset; 205 | 206 | /** Pins the bottom edge of the view to the bottom layout guide of the given view controller with an inset as a maximum or minimum. Available on iOS only. */ 207 | - (NSLayoutConstraint *)autoPinToBottomLayoutGuideOfViewController:(UIViewController *)viewController withInset:(CGFloat)inset relation:(NSLayoutRelation)relation; 208 | 209 | #endif /* TARGET_OS_IPHONE */ 210 | 211 | @end 212 | 213 | __PL_ASSUME_NONNULL_END 214 | -------------------------------------------------------------------------------- /XTrello/PureLayout/NSArray+PureLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+PureLayout.h 3 | // https://github.com/PureLayout/PureLayout 4 | // 5 | // Copyright (c) 2012 Richard Turton 6 | // Copyright (c) 2013-2015 Tyler Fox 7 | // 8 | // This code is distributed under the terms and conditions of the MIT license. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to 12 | // deal in the Software without restriction, including without limitation the 13 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 14 | // sell copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in 18 | // all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 26 | // IN THE SOFTWARE. 27 | // 28 | 29 | #import "PureLayoutDefines.h" 30 | 31 | 32 | __PL_ASSUME_NONNULL_BEGIN 33 | 34 | #pragma mark NSArray+PureLayout 35 | 36 | /** 37 | A category on NSArray that provides a simple yet powerful interface to: 38 | - Manage an array of Auto Layout constraints 39 | - Apply constraints to an array of views 40 | */ 41 | @interface NSArray (PureLayout) 42 | 43 | 44 | #pragma mark Array of Constraints 45 | 46 | /** Activates the constraints in this array. */ 47 | - (void)autoInstallConstraints; 48 | 49 | /** Deactivates the constraints in this array. */ 50 | - (void)autoRemoveConstraints; 51 | 52 | #if __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 53 | 54 | /** Sets the string as the identifier for the constraints in this array. Available in iOS 7.0 and OS X 10.9 and later. */ 55 | - (instancetype)autoIdentifyConstraints:(NSString *)identifier; 56 | 57 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 */ 58 | 59 | 60 | #pragma mark Array of Views 61 | 62 | /** Aligns views in this array to one another along a given edge. */ 63 | - (__NSArray_of(NSLayoutConstraint *) *)autoAlignViewsToEdge:(ALEdge)edge; 64 | 65 | /** Aligns views in this array to one another along a given axis. */ 66 | - (__NSArray_of(NSLayoutConstraint *) *)autoAlignViewsToAxis:(ALAxis)axis; 67 | 68 | /** Matches a given dimension of all the views in this array. */ 69 | - (__NSArray_of(NSLayoutConstraint *) *)autoMatchViewsDimension:(ALDimension)dimension; 70 | 71 | /** Sets the given dimension of all the views in this array to a given size. */ 72 | - (__NSArray_of(NSLayoutConstraint *) *)autoSetViewsDimension:(ALDimension)dimension toSize:(CGFloat)size; 73 | 74 | /** Sets all of the views in this array to a given size. */ 75 | - (__NSArray_of(NSLayoutConstraint *) *)autoSetViewsDimensionsToSize:(CGSize)size; 76 | 77 | 78 | /** Distributes the views in this array equally along the selected axis in their superview. 79 | Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them. */ 80 | - (__NSArray_of(NSLayoutConstraint *) *)autoDistributeViewsAlongAxis:(ALAxis)axis 81 | alignedTo:(ALAttribute)alignment 82 | withFixedSpacing:(CGFloat)spacing; 83 | 84 | /** Distributes the views in this array equally along the selected axis in their superview. 85 | Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them, with optional insets from the first and last views to their superview. */ 86 | - (__NSArray_of(NSLayoutConstraint *) *)autoDistributeViewsAlongAxis:(ALAxis)axis 87 | alignedTo:(ALAttribute)alignment 88 | withFixedSpacing:(CGFloat)spacing 89 | insetSpacing:(BOOL)shouldSpaceInsets; 90 | 91 | /** Distributes the views in this array equally along the selected axis in their superview. 92 | Views will have spacing (fixed) between them, with optional insets from the first and last views to their superview, and optionally constrained to the same size in the dimension along the axis. */ 93 | - (__NSArray_of(NSLayoutConstraint *) *)autoDistributeViewsAlongAxis:(ALAxis)axis 94 | alignedTo:(ALAttribute)alignment 95 | withFixedSpacing:(CGFloat)spacing 96 | insetSpacing:(BOOL)shouldSpaceInsets 97 | matchedSizes:(BOOL)shouldMatchSizes; 98 | 99 | 100 | /** Distributes the views in this array equally along the selected axis in their superview. 101 | Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them. */ 102 | - (__NSArray_of(NSLayoutConstraint *) *)autoDistributeViewsAlongAxis:(ALAxis)axis 103 | alignedTo:(ALAttribute)alignment 104 | withFixedSize:(CGFloat)size; 105 | 106 | /** Distributes the views in this array equally along the selected axis in their superview. 107 | Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them, with optional insets from the first and last views to their superview. */ 108 | - (__NSArray_of(NSLayoutConstraint *) *)autoDistributeViewsAlongAxis:(ALAxis)axis 109 | alignedTo:(ALAttribute)alignment 110 | withFixedSize:(CGFloat)size 111 | insetSpacing:(BOOL)shouldSpaceInsets; 112 | 113 | @end 114 | 115 | __PL_ASSUME_NONNULL_END 116 | -------------------------------------------------------------------------------- /XTrello/PureLayout/NSArray+PureLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+PureLayout.m 3 | // https://github.com/PureLayout/PureLayout 4 | // 5 | // Copyright (c) 2012 Richard Turton 6 | // Copyright (c) 2013-2015 Tyler Fox 7 | // 8 | // This code is distributed under the terms and conditions of the MIT license. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to 12 | // deal in the Software without restriction, including without limitation the 13 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 14 | // sell copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in 18 | // all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 26 | // IN THE SOFTWARE. 27 | // 28 | 29 | #import "NSArray+PureLayout.h" 30 | #import "ALView+PureLayout.h" 31 | #import "NSLayoutConstraint+PureLayout.h" 32 | #import "PureLayout+Internal.h" 33 | 34 | 35 | #pragma mark - NSArray+PureLayout 36 | 37 | @implementation NSArray (PureLayout) 38 | 39 | 40 | #pragma mark Array of Constraints 41 | 42 | /** 43 | Activates the constraints in this array. 44 | */ 45 | - (void)autoInstallConstraints 46 | { 47 | #if __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 48 | if ([NSLayoutConstraint respondsToSelector:@selector(activateConstraints:)]) { 49 | for (id object in self) { 50 | if ([object isKindOfClass:[NSLayoutConstraint class]]) { 51 | [NSLayoutConstraint al_applyGlobalStateToConstraint:object]; 52 | } 53 | } 54 | if ([NSLayoutConstraint al_preventAutomaticConstraintInstallation]) { 55 | [[NSLayoutConstraint al_currentArrayOfCreatedConstraints] addObjectsFromArray:self]; 56 | } else { 57 | [NSLayoutConstraint activateConstraints:self]; 58 | } 59 | return; 60 | } 61 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 */ 62 | 63 | for (id object in self) { 64 | if ([object isKindOfClass:[NSLayoutConstraint class]]) { 65 | [((NSLayoutConstraint *)object) autoInstall]; 66 | } 67 | } 68 | } 69 | 70 | /** 71 | Deactivates the constraints in this array. 72 | */ 73 | - (void)autoRemoveConstraints 74 | { 75 | #if __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 76 | if ([NSLayoutConstraint respondsToSelector:@selector(deactivateConstraints:)]) { 77 | [NSLayoutConstraint deactivateConstraints:self]; 78 | return; 79 | } 80 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 */ 81 | 82 | for (id object in self) { 83 | if ([object isKindOfClass:[NSLayoutConstraint class]]) { 84 | [((NSLayoutConstraint *)object) autoRemove]; 85 | } 86 | } 87 | } 88 | 89 | #if __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 90 | 91 | /** 92 | Sets the string as the identifier for the constraints in this array. Available in iOS 7.0 and OS X 10.9 and later. 93 | The identifier will be printed along with each constraint's description. 94 | This is helpful to document the constraints' purpose and aid in debugging. 95 | 96 | @param identifier A string used to identify the constraints in this array. 97 | @return This array. 98 | */ 99 | - (instancetype)autoIdentifyConstraints:(NSString *)identifier 100 | { 101 | for (id object in self) { 102 | if ([object isKindOfClass:[NSLayoutConstraint class]]) { 103 | [((NSLayoutConstraint *)object) autoIdentify:identifier]; 104 | } 105 | } 106 | return self; 107 | } 108 | 109 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 */ 110 | 111 | 112 | #pragma mark Array of Views 113 | 114 | /** 115 | Aligns views in this array to one another along a given edge. 116 | Note: This array must contain at least 2 views, and all views must share a common superview. 117 | 118 | @param edge The edge to which the views will be aligned. 119 | @return An array of constraints added. 120 | */ 121 | - (__NSArray_of(NSLayoutConstraint *) *)autoAlignViewsToEdge:(ALEdge)edge 122 | { 123 | NSAssert([self al_containsMinimumNumberOfViews:2], @"This array must contain at least 2 views."); 124 | __NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new]; 125 | ALView *previousView = nil; 126 | for (id object in self) { 127 | if ([object isKindOfClass:[ALView class]]) { 128 | ALView *view = (ALView *)object; 129 | view.translatesAutoresizingMaskIntoConstraints = NO; 130 | if (previousView) { 131 | [constraints addObject:[view autoPinEdge:edge toEdge:edge ofView:previousView]]; 132 | } 133 | previousView = view; 134 | } 135 | } 136 | return constraints; 137 | } 138 | 139 | /** 140 | Aligns views in this array to one another along a given axis. 141 | Note: This array must contain at least 2 views, and all views must share a common superview. 142 | 143 | @param axis The axis to which the views will be aligned. 144 | @return An array of constraints added. 145 | */ 146 | - (__NSArray_of(NSLayoutConstraint *) *)autoAlignViewsToAxis:(ALAxis)axis 147 | { 148 | NSAssert([self al_containsMinimumNumberOfViews:2], @"This array must contain at least 2 views."); 149 | __NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new]; 150 | ALView *previousView = nil; 151 | for (id object in self) { 152 | if ([object isKindOfClass:[ALView class]]) { 153 | ALView *view = (ALView *)object; 154 | view.translatesAutoresizingMaskIntoConstraints = NO; 155 | if (previousView) { 156 | [constraints addObject:[view autoAlignAxis:axis toSameAxisOfView:previousView]]; 157 | } 158 | previousView = view; 159 | } 160 | } 161 | return constraints; 162 | } 163 | 164 | /** 165 | Matches a given dimension of all the views in this array. 166 | Note: This array must contain at least 2 views, and all views must share a common superview. 167 | 168 | @param dimension The dimension to match for all of the views. 169 | @return An array of constraints added. 170 | */ 171 | - (__NSArray_of(NSLayoutConstraint *) *)autoMatchViewsDimension:(ALDimension)dimension 172 | { 173 | NSAssert([self al_containsMinimumNumberOfViews:2], @"This array must contain at least 2 views."); 174 | __NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new]; 175 | ALView *previousView = nil; 176 | for (id object in self) { 177 | if ([object isKindOfClass:[ALView class]]) { 178 | ALView *view = (ALView *)object; 179 | view.translatesAutoresizingMaskIntoConstraints = NO; 180 | if (previousView) { 181 | [constraints addObject:[view autoMatchDimension:dimension toDimension:dimension ofView:previousView]]; 182 | } 183 | previousView = view; 184 | } 185 | } 186 | return constraints; 187 | } 188 | 189 | /** 190 | Sets the given dimension of all the views in this array to a given size. 191 | Note: This array must contain at least 1 view. 192 | 193 | @param dimension The dimension of each of the views to set. 194 | @param size The size to set the given dimension of each view to. 195 | @return An array of constraints added. 196 | */ 197 | - (__NSArray_of(NSLayoutConstraint *) *)autoSetViewsDimension:(ALDimension)dimension toSize:(CGFloat)size 198 | { 199 | NSAssert([self al_containsMinimumNumberOfViews:1], @"This array must contain at least 1 view."); 200 | __NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new]; 201 | for (id object in self) { 202 | if ([object isKindOfClass:[ALView class]]) { 203 | ALView *view = (ALView *)object; 204 | view.translatesAutoresizingMaskIntoConstraints = NO; 205 | [constraints addObject:[view autoSetDimension:dimension toSize:size]]; 206 | } 207 | } 208 | return constraints; 209 | } 210 | 211 | /** 212 | Sets all of the views in this array to a given size. 213 | Note: This array must contain at least 1 view. 214 | 215 | @param size The size to set each view's dimensions to. 216 | @return An array of constraints added. 217 | */ 218 | - (__NSArray_of(NSLayoutConstraint *) *)autoSetViewsDimensionsToSize:(CGSize)size 219 | { 220 | __NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new]; 221 | [constraints addObjectsFromArray:[self autoSetViewsDimension:ALDimensionWidth toSize:size.width]]; 222 | [constraints addObjectsFromArray:[self autoSetViewsDimension:ALDimensionHeight toSize:size.height]]; 223 | return constraints; 224 | } 225 | 226 | 227 | /** 228 | Distributes the views in this array equally along the selected axis in their superview. 229 | Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them, 230 | including from the first and last views to their superview. 231 | 232 | @param axis The axis along which to distribute the views. 233 | @param alignment The attribute to use to align all the views to one another. 234 | @param spacing The fixed amount of spacing between each view. 235 | @return An array of constraints added. 236 | */ 237 | - (__NSArray_of(NSLayoutConstraint *) *)autoDistributeViewsAlongAxis:(ALAxis)axis 238 | alignedTo:(ALAttribute)alignment 239 | withFixedSpacing:(CGFloat)spacing 240 | { 241 | return [self autoDistributeViewsAlongAxis:axis 242 | alignedTo:alignment 243 | withFixedSpacing:spacing 244 | insetSpacing:YES]; 245 | } 246 | 247 | /** 248 | Distributes the views in this array equally along the selected axis in their superview. 249 | Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them. 250 | The first and last views can optionally be inset from their superview by the same amount of spacing as between views. 251 | 252 | @param axis The axis along which to distribute the views. 253 | @param alignment The attribute to use to align all the views to one another. 254 | @param spacing The fixed amount of spacing between each view. 255 | @param shouldSpaceInsets Whether the first and last views should be equally inset from their superview. 256 | @return An array of constraints added. 257 | */ 258 | - (__NSArray_of(NSLayoutConstraint *) *)autoDistributeViewsAlongAxis:(ALAxis)axis 259 | alignedTo:(ALAttribute)alignment 260 | withFixedSpacing:(CGFloat)spacing 261 | insetSpacing:(BOOL)shouldSpaceInsets 262 | { 263 | return [self autoDistributeViewsAlongAxis:axis 264 | alignedTo:alignment 265 | withFixedSpacing:spacing 266 | insetSpacing:shouldSpaceInsets 267 | matchedSizes:YES]; 268 | } 269 | 270 | /** 271 | Distributes the views in this array equally along the selected axis in their superview. 272 | Views will have fixed spacing between them, and can optionally be constrained to the same size in the dimension along the axis. 273 | The first and last views can optionally be inset from their superview by the same amount of spacing as between views. 274 | 275 | @param axis The axis along which to distribute the views. 276 | @param alignment The attribute to use to align all the views to one another. 277 | @param spacing The fixed amount of spacing between each view. 278 | @param shouldSpaceInsets Whether the first and last views should be equally inset from their superview. 279 | @param shouldMatchSizes Whether all views will be constrained to be the same size in the dimension along the axis. 280 | NOTE: All views must specify an intrinsic content size if passing NO, otherwise the layout will be ambiguous! 281 | @return An array of constraints added. 282 | */ 283 | - (__NSArray_of(NSLayoutConstraint *) *)autoDistributeViewsAlongAxis:(ALAxis)axis 284 | alignedTo:(ALAttribute)alignment 285 | withFixedSpacing:(CGFloat)spacing 286 | insetSpacing:(BOOL)shouldSpaceInsets 287 | matchedSizes:(BOOL)shouldMatchSizes 288 | { 289 | NSAssert([self al_containsMinimumNumberOfViews:1], @"This array must contain at least 1 view to distribute."); 290 | ALDimension matchedDimension; 291 | ALEdge firstEdge, lastEdge; 292 | switch (axis) { 293 | case ALAxisHorizontal: 294 | case ALAxisBaseline: // same value as ALAxisLastBaseline 295 | #if __PureLayout_MinBaseSDK_iOS_8_0 296 | case ALAxisFirstBaseline: 297 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 */ 298 | matchedDimension = ALDimensionWidth; 299 | firstEdge = ALEdgeLeading; 300 | lastEdge = ALEdgeTrailing; 301 | break; 302 | case ALAxisVertical: 303 | matchedDimension = ALDimensionHeight; 304 | firstEdge = ALEdgeTop; 305 | lastEdge = ALEdgeBottom; 306 | break; 307 | default: 308 | NSAssert(nil, @"Not a valid ALAxis."); 309 | return nil; 310 | } 311 | CGFloat leadingSpacing = shouldSpaceInsets ? spacing : 0.0; 312 | CGFloat trailingSpacing = shouldSpaceInsets ? spacing : 0.0; 313 | 314 | __NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new]; 315 | ALView *previousView = nil; 316 | for (id object in self) { 317 | if ([object isKindOfClass:[ALView class]]) { 318 | ALView *view = (ALView *)object; 319 | view.translatesAutoresizingMaskIntoConstraints = NO; 320 | if (previousView) { 321 | // Second, Third, ... View 322 | [constraints addObject:[view autoPinEdge:firstEdge toEdge:lastEdge ofView:previousView withOffset:spacing]]; 323 | if (shouldMatchSizes) { 324 | [constraints addObject:[view autoMatchDimension:matchedDimension toDimension:matchedDimension ofView:previousView]]; 325 | } 326 | [constraints addObject:[view al_alignAttribute:alignment toView:previousView forAxis:axis]]; 327 | } 328 | else { 329 | // First view 330 | [constraints addObject:[view autoPinEdgeToSuperviewEdge:firstEdge withInset:leadingSpacing]]; 331 | } 332 | previousView = view; 333 | } 334 | } 335 | if (previousView) { 336 | // Last View 337 | [constraints addObject:[previousView autoPinEdgeToSuperviewEdge:lastEdge withInset:trailingSpacing]]; 338 | } 339 | return constraints; 340 | } 341 | 342 | /** 343 | Distributes the views in this array equally along the selected axis in their superview. 344 | Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them, 345 | including from the first and last views to their superview. 346 | 347 | @param axis The axis along which to distribute the views. 348 | @param alignment The attribute to use to align all the views to one another. 349 | @param size The fixed size of each view in the dimension along the given axis. 350 | @return An array of constraints added. 351 | */ 352 | - (__NSArray_of(NSLayoutConstraint *) *)autoDistributeViewsAlongAxis:(ALAxis)axis 353 | alignedTo:(ALAttribute)alignment 354 | withFixedSize:(CGFloat)size 355 | { 356 | return [self autoDistributeViewsAlongAxis:axis 357 | alignedTo:alignment 358 | withFixedSize:size 359 | insetSpacing:YES]; 360 | } 361 | 362 | /** 363 | Distributes the views in this array equally along the selected axis in their superview. 364 | Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them. 365 | The first and last views can optionally be inset from their superview by the same amount of spacing as between views. 366 | 367 | @param axis The axis along which to distribute the views. 368 | @param alignment The attribute to use to align all the views to one another. 369 | @param size The fixed size of each view in the dimension along the given axis. 370 | @param shouldSpaceInsets Whether the first and last views should be equally inset from their superview. 371 | @return An array of constraints added. 372 | */ 373 | - (__NSArray_of(NSLayoutConstraint *) *)autoDistributeViewsAlongAxis:(ALAxis)axis 374 | alignedTo:(ALAttribute)alignment 375 | withFixedSize:(CGFloat)size 376 | insetSpacing:(BOOL)shouldSpaceInsets 377 | { 378 | NSAssert([self al_containsMinimumNumberOfViews:1], @"This array must contain at least 1 view to distribute."); 379 | ALDimension fixedDimension; 380 | NSLayoutAttribute attribute; 381 | switch (axis) { 382 | case ALAxisHorizontal: 383 | case ALAxisBaseline: // same value as ALAxisLastBaseline 384 | #if __PureLayout_MinBaseSDK_iOS_8_0 385 | case ALAxisFirstBaseline: 386 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 */ 387 | fixedDimension = ALDimensionWidth; 388 | attribute = NSLayoutAttributeCenterX; 389 | break; 390 | case ALAxisVertical: 391 | fixedDimension = ALDimensionHeight; 392 | attribute = NSLayoutAttributeCenterY; 393 | break; 394 | default: 395 | NSAssert(nil, @"Not a valid ALAxis."); 396 | return nil; 397 | } 398 | #if TARGET_OS_IPHONE 399 | # if !defined(PURELAYOUT_APP_EXTENSIONS) 400 | BOOL isRightToLeftLayout = [[UIApplication sharedApplication] userInterfaceLayoutDirection] == UIUserInterfaceLayoutDirectionRightToLeft; 401 | # else 402 | // App Extensions may not access -[UIApplication sharedApplication]; fall back to checking the bundle's preferred localization character direction 403 | BOOL isRightToLeftLayout = [NSLocale characterDirectionForLanguage:[[NSBundle mainBundle] preferredLocalizations][0]] == NSLocaleLanguageDirectionRightToLeft; 404 | # endif /* !defined(PURELAYOUT_APP_EXTENSIONS) */ 405 | #else 406 | BOOL isRightToLeftLayout = [[NSApplication sharedApplication] userInterfaceLayoutDirection] == NSUserInterfaceLayoutDirectionRightToLeft; 407 | #endif /* TARGET_OS_IPHONE */ 408 | BOOL shouldFlipOrder = isRightToLeftLayout && (axis != ALAxisVertical); // imitate the effect of leading/trailing when distributing horizontally 409 | 410 | __NSMutableArray_of(NSLayoutConstraint *) *constraints = [NSMutableArray new]; 411 | __NSArray_of(ALView *) *views = [self al_copyViewsOnly]; 412 | NSUInteger numberOfViews = [views count]; 413 | ALView *commonSuperview = [views al_commonSuperviewOfViews]; 414 | ALView *previousView = nil; 415 | for (NSUInteger i = 0; i < numberOfViews; i++) { 416 | ALView *view = shouldFlipOrder ? views[numberOfViews - i - 1] : views[i]; 417 | view.translatesAutoresizingMaskIntoConstraints = NO; 418 | [constraints addObject:[view autoSetDimension:fixedDimension toSize:size]]; 419 | CGFloat multiplier, constant; 420 | if (shouldSpaceInsets) { 421 | multiplier = (i * 2.0 + 2.0) / (numberOfViews + 1.0); 422 | constant = (multiplier - 1.0) * size / 2.0; 423 | } else { 424 | multiplier = (i * 2.0) / (numberOfViews - 1.0); 425 | constant = (-multiplier + 1.0) * size / 2.0; 426 | } 427 | // If the multiplier is very close to 0, set it to the minimum value to prevent the second item in the constraint from being lost. Filed as rdar://19168380 428 | if (fabs(multiplier) < kMULTIPLIER_MIN_VALUE) { 429 | multiplier = kMULTIPLIER_MIN_VALUE; 430 | } 431 | NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view attribute:attribute relatedBy:NSLayoutRelationEqual toItem:commonSuperview attribute:attribute multiplier:multiplier constant:constant]; 432 | [constraint autoInstall]; 433 | [constraints addObject:constraint]; 434 | if (previousView) { 435 | [constraints addObject:[view al_alignAttribute:alignment toView:previousView forAxis:axis]]; 436 | } 437 | previousView = view; 438 | } 439 | return constraints; 440 | } 441 | 442 | #pragma mark Internal Helper Methods 443 | 444 | /** 445 | Returns the common superview for the views in this array. If there is only one view in the array, its superview will be returned. 446 | Raises an exception if the views in this array do not share a common superview. 447 | 448 | @return The common superview for the views in this array. 449 | */ 450 | - (ALView *)al_commonSuperviewOfViews 451 | { 452 | ALView *commonSuperview = nil; 453 | ALView *previousView = nil; 454 | for (id object in self) { 455 | if ([object isKindOfClass:[ALView class]]) { 456 | ALView *view = (ALView *)object; 457 | if (previousView) { 458 | commonSuperview = [view al_commonSuperviewWithView:commonSuperview]; 459 | } else { 460 | commonSuperview = view.superview; 461 | } 462 | previousView = view; 463 | } 464 | } 465 | NSAssert(commonSuperview, @"Can't constrain views that do not share a common superview. Make sure that all the views in this array have been added into the same view hierarchy."); 466 | return commonSuperview; 467 | } 468 | 469 | /** 470 | Determines whether this array contains a minimum number of views. 471 | 472 | @param minimumNumberOfViews The minimum number of views to check for. 473 | @return YES if this array contains at least the minimum number of views, NO otherwise. 474 | */ 475 | - (BOOL)al_containsMinimumNumberOfViews:(NSUInteger)minimumNumberOfViews 476 | { 477 | NSUInteger numberOfViews = 0; 478 | for (id object in self) { 479 | if ([object isKindOfClass:[ALView class]]) { 480 | numberOfViews++; 481 | if (numberOfViews >= minimumNumberOfViews) { 482 | return YES; 483 | } 484 | } 485 | } 486 | return numberOfViews >= minimumNumberOfViews; 487 | } 488 | 489 | /** 490 | Creates a copy of this array containing only the view objects in it. 491 | 492 | @return A new array containing only the views that are in this array. 493 | */ 494 | - (__NSArray_of(ALView *) *)al_copyViewsOnly 495 | { 496 | __NSMutableArray_of(ALView *) *viewsOnlyArray = [NSMutableArray arrayWithCapacity:[self count]]; 497 | for (id object in self) { 498 | if ([object isKindOfClass:[ALView class]]) { 499 | [viewsOnlyArray addObject:object]; 500 | } 501 | } 502 | return viewsOnlyArray; 503 | } 504 | 505 | @end 506 | -------------------------------------------------------------------------------- /XTrello/PureLayout/NSLayoutConstraint+PureLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSLayoutConstraint+PureLayout.h 3 | // https://github.com/PureLayout/PureLayout 4 | // 5 | // Copyright (c) 2013-2015 Tyler Fox 6 | // 7 | // This code is distributed under the terms and conditions of the MIT license. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to 11 | // deal in the Software without restriction, including without limitation the 12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 13 | // sell copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 25 | // IN THE SOFTWARE. 26 | // 27 | 28 | #import "PureLayoutDefines.h" 29 | 30 | 31 | __PL_ASSUME_NONNULL_BEGIN 32 | 33 | #pragma mark NSLayoutConstraint+PureLayout 34 | 35 | /** 36 | A category on NSLayoutConstraint that allows constraints to be easily installed & removed. 37 | */ 38 | @interface NSLayoutConstraint (PureLayout) 39 | 40 | 41 | #pragma mark Batch Constraint Creation 42 | 43 | /** Creates all of the constraints in the block, then installs (activates) them all at once. 44 | All constraints created from calls to the PureLayout API in the block are returned in a single array. 45 | This may be more efficient than installing (activating) each constraint one-by-one. */ 46 | + (__NSArray_of(NSLayoutConstraint *) *)autoCreateAndInstallConstraints:(ALConstraintsBlock)block; 47 | 48 | /** Creates all of the constraints in the block but prevents them from being automatically installed (activated). 49 | All constraints created from calls to the PureLayout API in the block are returned in a single array. */ 50 | + (__NSArray_of(NSLayoutConstraint *) *)autoCreateConstraintsWithoutInstalling:(ALConstraintsBlock)block; 51 | 52 | 53 | #pragma mark Set Priority For Constraints 54 | 55 | /** Sets the constraint priority to the given value for all constraints created using the PureLayout API within the given constraints block. 56 | NOTE: This method will have no effect (and will NOT set the priority) on constraints created or added without using the PureLayout API! */ 57 | + (void)autoSetPriority:(ALLayoutPriority)priority forConstraints:(ALConstraintsBlock)block; 58 | 59 | 60 | #pragma mark Identify Constraints 61 | 62 | #if __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 63 | 64 | /** Sets the identifier for all constraints created using the PureLayout API within the given constraints block. 65 | NOTE: This method will have no effect (and will NOT set the identifier) on constraints created or added without using the PureLayout API! */ 66 | + (void)autoSetIdentifier:(NSString *)identifier forConstraints:(ALConstraintsBlock)block; 67 | 68 | /** Sets the string as the identifier for this constraint. Available in iOS 7.0 and OS X 10.9 and later. */ 69 | - (instancetype)autoIdentify:(NSString *)identifier; 70 | 71 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 */ 72 | 73 | 74 | #pragma mark Install & Remove Constraints 75 | 76 | /** Activates the the constraint. */ 77 | - (void)autoInstall; 78 | 79 | /** Deactivates the constraint. */ 80 | - (void)autoRemove; 81 | 82 | @end 83 | 84 | __PL_ASSUME_NONNULL_END 85 | -------------------------------------------------------------------------------- /XTrello/PureLayout/NSLayoutConstraint+PureLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSLayoutConstraint+PureLayout.m 3 | // https://github.com/PureLayout/PureLayout 4 | // 5 | // Copyright (c) 2013-2015 Tyler Fox 6 | // 7 | // This code is distributed under the terms and conditions of the MIT license. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to 11 | // deal in the Software without restriction, including without limitation the 12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 13 | // sell copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 25 | // IN THE SOFTWARE. 26 | // 27 | 28 | #import "NSLayoutConstraint+PureLayout.h" 29 | #import "ALView+PureLayout.h" 30 | #import "NSArray+PureLayout.h" 31 | #import "PureLayout+Internal.h" 32 | 33 | 34 | #pragma mark - NSLayoutConstraint+PureLayout 35 | 36 | @implementation NSLayoutConstraint (PureLayout) 37 | 38 | #pragma mark Batch Constraint Creation 39 | 40 | /** 41 | A global variable that stores a stack of arrays of constraints created without being immediately installed. 42 | When executing a constraints block passed into the +[autoCreateConstraintsWithoutInstalling:] method, a new 43 | mutable array is pushed onto this stack, and all constraints created with PureLayout in the block are added 44 | to this array. When the block finishes executing, the array is popped off this stack. Automatic constraint 45 | installation is prevented if this stack contains at least 1 array. 46 | 47 | NOTE: Access to this variable is not synchronized (and should only be done on the main thread). 48 | */ 49 | static __NSMutableArray_of(__NSMutableArray_of(NSLayoutConstraint *) *) *_al_arraysOfCreatedConstraints = nil; 50 | 51 | /** 52 | A global variable that is set to YES when installing a batch of constraints collected from a call to +[autoCreateAndInstallConstraints]. 53 | When this flag is YES, constraints are installed immediately without checking for or adding to the +[al_currentArrayOfCreatedConstraints]. 54 | This is necessary to properly handle nested calls to +[autoCreateAndInstallConstraints], where calls whose block contains other call(s) 55 | should not return constraints from within the blocks of nested call(s). 56 | */ 57 | static BOOL _al_isInstallingCreatedConstraints = NO; 58 | 59 | /** 60 | Accessor for the global state that stores arrays of constraints created without being installed. 61 | */ 62 | + (__NSMutableArray_of(__NSMutableArray_of(NSLayoutConstraint *) *) *)al_arraysOfCreatedConstraints 63 | { 64 | NSAssert([NSThread isMainThread], @"PureLayout is not thread safe, and must be used exclusively from the main thread."); 65 | if (!_al_arraysOfCreatedConstraints) { 66 | _al_arraysOfCreatedConstraints = [NSMutableArray new]; 67 | } 68 | return _al_arraysOfCreatedConstraints; 69 | } 70 | 71 | /** 72 | Accessor for the current mutable array of constraints created without being immediately installed. 73 | */ 74 | + (__NSMutableArray_of(NSLayoutConstraint *) *)al_currentArrayOfCreatedConstraints 75 | { 76 | return [[self al_arraysOfCreatedConstraints] lastObject]; 77 | } 78 | 79 | /** 80 | Accessor for the global state that determines whether automatic constraint installation should be prevented. 81 | */ 82 | + (BOOL)al_preventAutomaticConstraintInstallation 83 | { 84 | return (_al_isInstallingCreatedConstraints == NO) && ([[self al_arraysOfCreatedConstraints] count] > 0); 85 | } 86 | 87 | /** 88 | Creates all of the constraints in the block, then installs (activates) them all at once. 89 | All constraints created from calls to the PureLayout API in the block are returned in a single array. 90 | This may be more efficient than installing (activating) each constraint one-by-one. 91 | 92 | Note: calls to this method may be nested. The constraints returned from a call will NOT include constraints 93 | created in nested calls; constraints are only returned from the inner-most call they are created within. 94 | 95 | @param block A block of method calls to the PureLayout API that create constraints. 96 | @return An array of the constraints that were created from calls to the PureLayout API inside the block. 97 | */ 98 | + (__NSArray_of(NSLayoutConstraint *) *)autoCreateAndInstallConstraints:(ALConstraintsBlock)block 99 | { 100 | NSArray *createdConstraints = [self autoCreateConstraintsWithoutInstalling:block]; 101 | _al_isInstallingCreatedConstraints = YES; 102 | [createdConstraints autoInstallConstraints]; 103 | _al_isInstallingCreatedConstraints = NO; 104 | return createdConstraints; 105 | } 106 | 107 | /** 108 | Creates all of the constraints in the block but prevents them from being automatically installed (activated). 109 | All constraints created from calls to the PureLayout API in the block are returned in a single array. 110 | 111 | Note: calls to this method may be nested. The constraints returned from a call will NOT include constraints 112 | created in nested calls; constraints are only returned from the inner-most call they are created within. 113 | 114 | @param block A block of method calls to the PureLayout API that create constraints. 115 | @return An array of the constraints that were created from calls to the PureLayout API inside the block. 116 | */ 117 | + (__NSArray_of(NSLayoutConstraint *) *)autoCreateConstraintsWithoutInstalling:(ALConstraintsBlock)block 118 | { 119 | NSAssert(block, @"The constraints block cannot be nil."); 120 | NSArray *createdConstraints = nil; 121 | if (block) { 122 | [[self al_arraysOfCreatedConstraints] addObject:[NSMutableArray new]]; 123 | block(); 124 | createdConstraints = [self al_currentArrayOfCreatedConstraints]; 125 | [[self al_arraysOfCreatedConstraints] removeLastObject]; 126 | } 127 | return createdConstraints; 128 | } 129 | 130 | 131 | #pragma mark Set Priority For Constraints 132 | 133 | /** 134 | A global variable that stores a stack of layout priorities to set on constraints. 135 | When executing a constraints block passed into the +[autoSetPriority:forConstraints:] method, the priority for 136 | that call is pushed onto this stack, and when the block finishes executing, that priority is popped off this 137 | stack. If this stack contains at least 1 priority, the priority at the top of the stack will be set for all 138 | constraints created by this library (even if automatic constraint installation is being prevented). 139 | NOTE: Access to this variable is not synchronized (and should only be done on the main thread). 140 | */ 141 | static __NSMutableArray_of(NSNumber *) *_al_globalConstraintPriorities = nil; 142 | 143 | /** 144 | Accessor for the global stack of layout priorities. 145 | */ 146 | + (__NSMutableArray_of(NSNumber *) *)al_globalConstraintPriorities 147 | { 148 | NSAssert([NSThread isMainThread], @"PureLayout is not thread safe, and must be used exclusively from the main thread."); 149 | if (!_al_globalConstraintPriorities) { 150 | _al_globalConstraintPriorities = [NSMutableArray new]; 151 | } 152 | return _al_globalConstraintPriorities; 153 | } 154 | 155 | /** 156 | Returns the current layout priority to use for constraints. 157 | When executing a constraints block passed into +[autoSetPriority:forConstraints:], this will return 158 | the priority for the current block. Otherwise, the default Required priority is returned. 159 | */ 160 | + (ALLayoutPriority)al_currentGlobalConstraintPriority 161 | { 162 | __NSMutableArray_of(NSNumber *) *globalConstraintPriorities = [self al_globalConstraintPriorities]; 163 | if ([globalConstraintPriorities count] == 0) { 164 | return ALLayoutPriorityRequired; 165 | } 166 | return [[globalConstraintPriorities lastObject] floatValue]; 167 | } 168 | 169 | /** 170 | Accessor for the global state that determines if we're currently in the scope of a priority constraints block. 171 | */ 172 | + (BOOL)al_isExecutingPriorityConstraintsBlock 173 | { 174 | return [[self al_globalConstraintPriorities] count] > 0; 175 | } 176 | 177 | /** 178 | Sets the constraint priority to the given value for all constraints created using the PureLayout 179 | API within the given constraints block. 180 | 181 | NOTE: This method will have no effect (and will NOT set the priority) on constraints created or added 182 | without using the PureLayout API! 183 | 184 | @param priority The layout priority to be set on all constraints created in the constraints block. 185 | @param block A block of method calls to the PureLayout API that create and install constraints. 186 | */ 187 | + (void)autoSetPriority:(ALLayoutPriority)priority forConstraints:(ALConstraintsBlock)block 188 | { 189 | NSAssert(block, @"The constraints block cannot be nil."); 190 | if (block) { 191 | [[self al_globalConstraintPriorities] addObject:@(priority)]; 192 | block(); 193 | [[self al_globalConstraintPriorities] removeLastObject]; 194 | } 195 | } 196 | 197 | 198 | #pragma mark Identify Constraints 199 | 200 | #if __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 201 | 202 | /** 203 | A global variable that stores a stack of identifier strings to set on constraints. 204 | When executing a constraints block passed into the +[autoSetIdentifier:forConstraints:] method, the identifier for 205 | that call is pushed onto this stack, and when the block finishes executing, that identifier is popped off this 206 | stack. If this stack contains at least 1 identifier, the identifier at the top of the stack will be set for all 207 | constraints created by this library (even if automatic constraint installation is being prevented). 208 | NOTE: Access to this variable is not synchronized (and should only be done on the main thread). 209 | */ 210 | static __NSMutableArray_of(NSString *) *_al_globalConstraintIdentifiers = nil; 211 | 212 | /** 213 | Accessor for the global state of constraint identifiers. 214 | */ 215 | + (__NSMutableArray_of(NSString *) *)al_globalConstraintIdentifiers 216 | { 217 | NSAssert([NSThread isMainThread], @"PureLayout is not thread safe, and must be used exclusively from the main thread."); 218 | if (!_al_globalConstraintIdentifiers) { 219 | _al_globalConstraintIdentifiers = [NSMutableArray new]; 220 | } 221 | return _al_globalConstraintIdentifiers; 222 | } 223 | 224 | /** 225 | Returns the current identifier string to use for constraints. 226 | When executing a constraints block passed into +[autoSetIdentifier:forConstraints:], this will return 227 | the identifier for the current block. Otherwise, nil is returned. 228 | */ 229 | + (NSString *)al_currentGlobalConstraintIdentifier 230 | { 231 | __NSMutableArray_of(NSString *) *globalConstraintIdentifiers = [self al_globalConstraintIdentifiers]; 232 | if ([globalConstraintIdentifiers count] == 0) { 233 | return nil; 234 | } 235 | return [globalConstraintIdentifiers lastObject]; 236 | } 237 | 238 | /** 239 | Sets the identifier for all constraints created using the PureLayout API within the given constraints block. 240 | 241 | NOTE: This method will have no effect (and will NOT set the identifier) on constraints created or added 242 | without using the PureLayout API! 243 | 244 | @param identifier A string used to identify all constraints created in the constraints block. 245 | @param block A block of method calls to the PureLayout API that create and install constraints. 246 | */ 247 | + (void)autoSetIdentifier:(NSString *)identifier forConstraints:(ALConstraintsBlock)block 248 | { 249 | NSAssert(block, @"The constraints block cannot be nil."); 250 | NSAssert(identifier, @"The identifier string cannot be nil."); 251 | if (block) { 252 | if (identifier) { 253 | [[self al_globalConstraintIdentifiers] addObject:identifier]; 254 | } 255 | block(); 256 | if (identifier) { 257 | [[self al_globalConstraintIdentifiers] removeLastObject]; 258 | } 259 | } 260 | } 261 | 262 | /** 263 | Sets the string as the identifier for this constraint. Available in iOS 7.0 and OS X 10.9 and later. 264 | The identifier will be printed along with the constraint's description. 265 | This is helpful to document a constraint's purpose and aid in debugging. 266 | 267 | @param identifier A string used to identify this constraint. 268 | @return This constraint. 269 | */ 270 | - (instancetype)autoIdentify:(NSString *)identifier 271 | { 272 | if ([self respondsToSelector:@selector(setIdentifier:)]) { 273 | self.identifier = identifier; 274 | } 275 | return self; 276 | } 277 | 278 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 */ 279 | 280 | 281 | #pragma mark Install & Remove Constraints 282 | 283 | /** 284 | Activates the constraint. 285 | */ 286 | - (void)autoInstall 287 | { 288 | #if __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 289 | if ([self respondsToSelector:@selector(setActive:)]) { 290 | [NSLayoutConstraint al_applyGlobalStateToConstraint:self]; 291 | if ([NSLayoutConstraint al_preventAutomaticConstraintInstallation]) { 292 | [[NSLayoutConstraint al_currentArrayOfCreatedConstraints] addObject:self]; 293 | } else { 294 | self.active = YES; 295 | } 296 | return; 297 | } 298 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 */ 299 | 300 | NSAssert(self.firstItem || self.secondItem, @"Can't install a constraint with nil firstItem and secondItem."); 301 | if (self.firstItem) { 302 | if (self.secondItem) { 303 | NSAssert([self.firstItem isKindOfClass:[ALView class]] && [self.secondItem isKindOfClass:[ALView class]], @"Can only automatically install a constraint if both items are views."); 304 | ALView *commonSuperview = [self.firstItem al_commonSuperviewWithView:self.secondItem]; 305 | [commonSuperview al_addConstraint:self]; 306 | } else { 307 | NSAssert([self.firstItem isKindOfClass:[ALView class]], @"Can only automatically install a constraint if the item is a view."); 308 | [self.firstItem al_addConstraint:self]; 309 | } 310 | } else { 311 | NSAssert([self.secondItem isKindOfClass:[ALView class]], @"Can only automatically install a constraint if the item is a view."); 312 | [self.secondItem al_addConstraint:self]; 313 | } 314 | } 315 | 316 | /** 317 | Deactivates the constraint. 318 | */ 319 | - (void)autoRemove 320 | { 321 | #if __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 322 | if ([self respondsToSelector:@selector(setActive:)]) { 323 | self.active = NO; 324 | return; 325 | } 326 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 */ 327 | 328 | if (self.secondItem) { 329 | ALView *commonSuperview = [self.firstItem al_commonSuperviewWithView:self.secondItem]; 330 | while (commonSuperview) { 331 | if ([commonSuperview.constraints containsObject:self]) { 332 | [commonSuperview removeConstraint:self]; 333 | return; 334 | } 335 | commonSuperview = commonSuperview.superview; 336 | } 337 | } 338 | else { 339 | [self.firstItem removeConstraint:self]; 340 | return; 341 | } 342 | NSAssert(nil, @"Failed to remove constraint: %@", self); 343 | } 344 | 345 | 346 | #pragma mark Internal Methods 347 | 348 | /** 349 | Applies the global constraint priority and identifier to the given constraint. 350 | This should be done before installing all constraints. 351 | 352 | @param constraint The constraint to set the global priority and identifier on. 353 | */ 354 | + (void)al_applyGlobalStateToConstraint:(NSLayoutConstraint *)constraint 355 | { 356 | if ([NSLayoutConstraint al_isExecutingPriorityConstraintsBlock]) { 357 | constraint.priority = [NSLayoutConstraint al_currentGlobalConstraintPriority]; 358 | } 359 | #if __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 360 | NSString *globalConstraintIdentifier = [NSLayoutConstraint al_currentGlobalConstraintIdentifier]; 361 | if (globalConstraintIdentifier) { 362 | [constraint autoIdentify:globalConstraintIdentifier]; 363 | } 364 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 */ 365 | } 366 | 367 | /** 368 | Returns the corresponding NSLayoutAttribute for the given ALAttribute. 369 | 370 | @return The layout attribute for the given ALAttribute. 371 | */ 372 | + (NSLayoutAttribute)al_layoutAttributeForAttribute:(ALAttribute)attribute 373 | { 374 | NSLayoutAttribute layoutAttribute = NSLayoutAttributeNotAnAttribute; 375 | switch (attribute) { 376 | case ALEdgeLeft: 377 | layoutAttribute = NSLayoutAttributeLeft; 378 | break; 379 | case ALEdgeRight: 380 | layoutAttribute = NSLayoutAttributeRight; 381 | break; 382 | case ALEdgeTop: 383 | layoutAttribute = NSLayoutAttributeTop; 384 | break; 385 | case ALEdgeBottom: 386 | layoutAttribute = NSLayoutAttributeBottom; 387 | break; 388 | case ALEdgeLeading: 389 | layoutAttribute = NSLayoutAttributeLeading; 390 | break; 391 | case ALEdgeTrailing: 392 | layoutAttribute = NSLayoutAttributeTrailing; 393 | break; 394 | case ALDimensionWidth: 395 | layoutAttribute = NSLayoutAttributeWidth; 396 | break; 397 | case ALDimensionHeight: 398 | layoutAttribute = NSLayoutAttributeHeight; 399 | break; 400 | case ALAxisVertical: 401 | layoutAttribute = NSLayoutAttributeCenterX; 402 | break; 403 | case ALAxisHorizontal: 404 | layoutAttribute = NSLayoutAttributeCenterY; 405 | break; 406 | case ALAxisBaseline: // same value as ALAxisLastBaseline 407 | layoutAttribute = NSLayoutAttributeBaseline; 408 | break; 409 | #if __PureLayout_MinBaseSDK_iOS_8_0 410 | case ALAxisFirstBaseline: 411 | NSAssert(__PureLayout_MinSysVer_iOS_8_0, @"ALAxisFirstBaseline is only supported on iOS 8.0 or higher."); 412 | layoutAttribute = NSLayoutAttributeFirstBaseline; 413 | break; 414 | case ALMarginLeft: 415 | NSAssert(__PureLayout_MinSysVer_iOS_8_0, @"ALEdgeLeftMargin is only supported on iOS 8.0 or higher."); 416 | layoutAttribute = NSLayoutAttributeLeftMargin; 417 | break; 418 | case ALMarginRight: 419 | NSAssert(__PureLayout_MinSysVer_iOS_8_0, @"ALEdgeRightMargin is only supported on iOS 8.0 or higher."); 420 | layoutAttribute = NSLayoutAttributeRightMargin; 421 | break; 422 | case ALMarginTop: 423 | NSAssert(__PureLayout_MinSysVer_iOS_8_0, @"ALEdgeTopMargin is only supported on iOS 8.0 or higher."); 424 | layoutAttribute = NSLayoutAttributeTopMargin; 425 | break; 426 | case ALMarginBottom: 427 | NSAssert(__PureLayout_MinSysVer_iOS_8_0, @"ALEdgeBottomMargin is only supported on iOS 8.0 or higher."); 428 | layoutAttribute = NSLayoutAttributeBottomMargin; 429 | break; 430 | case ALMarginLeading: 431 | NSAssert(__PureLayout_MinSysVer_iOS_8_0, @"ALEdgeLeadingMargin is only supported on iOS 8.0 or higher."); 432 | layoutAttribute = NSLayoutAttributeLeadingMargin; 433 | break; 434 | case ALMarginTrailing: 435 | NSAssert(__PureLayout_MinSysVer_iOS_8_0, @"ALEdgeTrailingMargin is only supported on iOS 8.0 or higher."); 436 | layoutAttribute = NSLayoutAttributeTrailingMargin; 437 | break; 438 | case ALMarginAxisVertical: 439 | NSAssert(__PureLayout_MinSysVer_iOS_8_0, @"ALAxisVerticalMargin is only supported on iOS 8.0 or higher."); 440 | layoutAttribute = NSLayoutAttributeCenterXWithinMargins; 441 | break; 442 | case ALMarginAxisHorizontal: 443 | NSAssert(__PureLayout_MinSysVer_iOS_8_0, @"ALAxisHorizontalMargin is only supported on iOS 8.0 or higher."); 444 | layoutAttribute = NSLayoutAttributeCenterYWithinMargins; 445 | break; 446 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 */ 447 | default: 448 | NSAssert(nil, @"Not a valid ALAttribute."); 449 | break; 450 | } 451 | return layoutAttribute; 452 | } 453 | 454 | /** 455 | Returns the corresponding ALLayoutConstraintAxis for the given ALAxis. 456 | 457 | @return The constraint axis for the given axis. 458 | */ 459 | + (ALLayoutConstraintAxis)al_constraintAxisForAxis:(ALAxis)axis 460 | { 461 | ALLayoutConstraintAxis constraintAxis; 462 | switch (axis) { 463 | case ALAxisVertical: 464 | constraintAxis = ALLayoutConstraintAxisVertical; 465 | break; 466 | case ALAxisHorizontal: 467 | case ALAxisBaseline: // same value as ALAxisLastBaseline 468 | #if __PureLayout_MinBaseSDK_iOS_8_0 469 | case ALAxisFirstBaseline: 470 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 */ 471 | constraintAxis = ALLayoutConstraintAxisHorizontal; 472 | break; 473 | default: 474 | NSAssert(nil, @"Not a valid ALAxis."); 475 | constraintAxis = ALLayoutConstraintAxisHorizontal; // default to an arbitrary value to satisfy the compiler 476 | break; 477 | } 478 | return constraintAxis; 479 | } 480 | 481 | #if __PureLayout_MinBaseSDK_iOS_8_0 482 | 483 | /** 484 | Returns the corresponding margin for the given edge. 485 | 486 | @param edge The edge to convert to the corresponding margin. 487 | @return The margin for the given edge. 488 | */ 489 | + (ALMargin)al_marginForEdge:(ALEdge)edge 490 | { 491 | NSAssert(__PureLayout_MinSysVer_iOS_8_0, @"Margin attributes are only supported on iOS 8.0 or higher."); 492 | ALMargin margin; 493 | switch (edge) { 494 | case ALEdgeLeft: 495 | margin = ALMarginLeft; 496 | break; 497 | case ALEdgeRight: 498 | margin = ALMarginRight; 499 | break; 500 | case ALEdgeTop: 501 | margin = ALMarginTop; 502 | break; 503 | case ALEdgeBottom: 504 | margin = ALMarginBottom; 505 | break; 506 | case ALEdgeLeading: 507 | margin = ALMarginLeading; 508 | break; 509 | case ALEdgeTrailing: 510 | margin = ALMarginTrailing; 511 | break; 512 | default: 513 | NSAssert(nil, @"Not a valid ALEdge."); 514 | margin = ALMarginLeft; // default to an arbitrary value to satisfy the compiler 515 | break; 516 | } 517 | return margin; 518 | } 519 | 520 | /** 521 | Returns the corresponding margin axis for the given axis. 522 | 523 | @param axis The axis to convert to the corresponding margin axis. 524 | @return The margin axis for the given axis. 525 | */ 526 | + (ALMarginAxis)al_marginAxisForAxis:(ALAxis)axis 527 | { 528 | NSAssert(__PureLayout_MinSysVer_iOS_8_0, @"Margin attributes are only supported on iOS 8.0 or higher."); 529 | ALMarginAxis marginAxis; 530 | switch (axis) { 531 | case ALAxisVertical: 532 | marginAxis = ALMarginAxisVertical; 533 | break; 534 | case ALAxisHorizontal: 535 | marginAxis = ALMarginAxisHorizontal; 536 | break; 537 | case ALAxisBaseline: 538 | case ALAxisFirstBaseline: 539 | NSAssert(nil, @"The baseline axis attributes do not have corresponding margin axis attributes."); 540 | marginAxis = ALMarginAxisVertical; // default to an arbitrary value to satisfy the compiler 541 | break; 542 | default: 543 | NSAssert(nil, @"Not a valid ALAxis."); 544 | marginAxis = ALMarginAxisVertical; // default to an arbitrary value to satisfy the compiler 545 | break; 546 | } 547 | return marginAxis; 548 | } 549 | 550 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 */ 551 | 552 | @end 553 | -------------------------------------------------------------------------------- /XTrello/PureLayout/PureLayout+Internal.h: -------------------------------------------------------------------------------- 1 | // 2 | // PureLayout+Internal.h 3 | // https://github.com/PureLayout/PureLayout 4 | // 5 | // Copyright (c) 2014-2015 Tyler Fox 6 | // 7 | // This code is distributed under the terms and conditions of the MIT license. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to 11 | // deal in the Software without restriction, including without limitation the 12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 13 | // sell copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 25 | // IN THE SOFTWARE. 26 | // 27 | 28 | #import "PureLayoutDefines.h" 29 | 30 | 31 | // Using generics with NSMutableArray is so common in the internal implementation of PureLayout that it gets a dedicated preprocessor macro for better readability. 32 | #define __NSMutableArray_of(type) __PL_GENERICS(NSMutableArray, type) 33 | 34 | __PL_ASSUME_NONNULL_BEGIN 35 | 36 | /** A constant that represents the smallest valid positive value for the multiplier of a constraint, 37 | since a value of 0 will cause the second item to be lost in the internal auto layout engine. */ 38 | static const CGFloat kMULTIPLIER_MIN_VALUE = (CGFloat)0.00001; // very small floating point numbers (e.g. CGFLOAT_MIN) can cause problems 39 | 40 | 41 | /** 42 | A category that exposes the internal (private) helper methods of the ALView+PureLayout category. 43 | */ 44 | @interface ALView (PureLayoutInternal) 45 | 46 | - (void)al_addConstraint:(NSLayoutConstraint *)constraint; 47 | - (ALView *)al_commonSuperviewWithView:(ALView *)otherView; 48 | - (NSLayoutConstraint *)al_alignAttribute:(ALAttribute)attribute toView:(ALView *)otherView forAxis:(ALAxis)axis; 49 | 50 | @end 51 | 52 | 53 | /** 54 | A category that exposes the internal (private) helper methods of the NSArray+PureLayout category. 55 | */ 56 | @interface NSArray (PureLayoutInternal) 57 | 58 | - (ALView *)al_commonSuperviewOfViews; 59 | - (BOOL)al_containsMinimumNumberOfViews:(NSUInteger)minimumNumberOfViews; 60 | - (__NSArray_of(ALView *) *)al_copyViewsOnly; 61 | 62 | @end 63 | 64 | 65 | /** 66 | A category that exposes the internal (private) helper methods of the NSLayoutConstraint+PureLayout category. 67 | */ 68 | @interface NSLayoutConstraint (PureLayoutInternal) 69 | 70 | + (BOOL)al_preventAutomaticConstraintInstallation; 71 | + (__NSMutableArray_of(NSLayoutConstraint *) *)al_currentArrayOfCreatedConstraints; 72 | + (BOOL)al_isExecutingPriorityConstraintsBlock; 73 | + (ALLayoutPriority)al_currentGlobalConstraintPriority; 74 | #if __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 75 | + (NSString *)al_currentGlobalConstraintIdentifier; 76 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 || __PureLayout_MinBaseSDK_OSX_10_10 */ 77 | + (void)al_applyGlobalStateToConstraint:(NSLayoutConstraint *)constraint; 78 | + (NSLayoutAttribute)al_layoutAttributeForAttribute:(ALAttribute)attribute; 79 | + (ALLayoutConstraintAxis)al_constraintAxisForAxis:(ALAxis)axis; 80 | #if __PureLayout_MinBaseSDK_iOS_8_0 81 | + (ALMargin)al_marginForEdge:(ALEdge)edge; 82 | + (ALMarginAxis)al_marginAxisForAxis:(ALAxis)axis; 83 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 */ 84 | 85 | @end 86 | 87 | __PL_ASSUME_NONNULL_END 88 | -------------------------------------------------------------------------------- /XTrello/PureLayout/PureLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // PureLayout.h 3 | // https://github.com/PureLayout/PureLayout 4 | // 5 | // Copyright (c) 2014-2015 Tyler Fox 6 | // 7 | // This code is distributed under the terms and conditions of the MIT license. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to 11 | // deal in the Software without restriction, including without limitation the 12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 13 | // sell copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 25 | // IN THE SOFTWARE. 26 | // 27 | 28 | #ifndef PureLayout_h 29 | #define PureLayout_h 30 | 31 | #import 32 | 33 | //! Project version number for PureLayout. 34 | FOUNDATION_EXPORT double PureLayoutVersionNumber; 35 | 36 | //! Project version string for PureLayout. 37 | FOUNDATION_EXPORT const unsigned char PureLayoutVersionString[]; 38 | 39 | #import "ALView+PureLayout.h" 40 | #import "NSArray+PureLayout.h" 41 | #import "NSLayoutConstraint+PureLayout.h" 42 | 43 | #endif /* PureLayout_h */ 44 | -------------------------------------------------------------------------------- /XTrello/PureLayout/PureLayoutDefines.h: -------------------------------------------------------------------------------- 1 | // 2 | // PureLayoutDefines.h 3 | // https://github.com/PureLayout/PureLayout 4 | // 5 | // Copyright (c) 2014-2015 Tyler Fox 6 | // 7 | // This code is distributed under the terms and conditions of the MIT license. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to 11 | // deal in the Software without restriction, including without limitation the 12 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 13 | // sell copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 25 | // IN THE SOFTWARE. 26 | // 27 | 28 | #ifndef PureLayoutDefines_h 29 | #define PureLayoutDefines_h 30 | 31 | #import 32 | 33 | // Define some preprocessor macros to check for a minimum Base SDK. These are used to prevent compile-time errors in older versions of Xcode. 34 | #define __PureLayout_MinBaseSDK_iOS_8_0 (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_7_1) 35 | #define __PureLayout_MinBaseSDK_OSX_10_10 (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MAX_ALLOWED > __MAC_10_9) 36 | 37 | // Define some preprocessor macros to check for a minimum System Version. These are used to prevent runtime crashes on older versions of iOS/OS X. 38 | #define __PureLayout_MinSysVer_iOS_7_0 (TARGET_OS_IPHONE && floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) 39 | #define __PureLayout_MinSysVer_iOS_8_0 (TARGET_OS_IPHONE && floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1) 40 | #define __PureLayout_MinSysVer_OSX_10_9 (!TARGET_OS_IPHONE && floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_8_4) 41 | 42 | // Define some preprocessor macros that allow nullability annotations to be adopted in a backwards-compatible manner. 43 | #if __has_feature(nullability) 44 | # define __PL_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN 45 | # define __PL_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END 46 | #else 47 | # define __PL_ASSUME_NONNULL_BEGIN 48 | # define __PL_ASSUME_NONNULL_END 49 | #endif 50 | 51 | // Define some preprocessor macros that allow generics to be adopted in a backwards-compatible manner. 52 | #if __has_feature(objc_generics) 53 | # define __PL_GENERICS(class, ...) class<__VA_ARGS__> 54 | #else 55 | # define __PL_GENERICS(class, ...) class 56 | #endif 57 | 58 | // Using generics with NSArray is so common in PureLayout that it gets a dedicated preprocessor macro for better readability. 59 | #define __NSArray_of(type) __PL_GENERICS(NSArray, type) 60 | 61 | // Define generic AL-prefixed macros for the types/constants/etc that have slight naming variations across iOS and OS X, which allows the same code to be platform-independent. 62 | #if TARGET_OS_IPHONE || TARGET_OS_TV 63 | # import 64 | # define ALView UIView 65 | # define ALEdgeInsets UIEdgeInsets 66 | # define ALEdgeInsetsZero UIEdgeInsetsZero 67 | # define ALEdgeInsetsMake UIEdgeInsetsMake 68 | # define ALLayoutConstraintAxis UILayoutConstraintAxis 69 | # define ALLayoutConstraintOrientation ALLayoutConstraintAxis 70 | # define ALLayoutConstraintAxisHorizontal UILayoutConstraintAxisHorizontal 71 | # define ALLayoutConstraintAxisVertical UILayoutConstraintAxisVertical 72 | # define ALLayoutConstraintOrientationHorizontal ALLayoutConstraintAxisHorizontal 73 | # define ALLayoutConstraintOrientationVertical ALLayoutConstraintAxisVertical 74 | # define ALLayoutPriority UILayoutPriority 75 | # define ALLayoutPriorityRequired UILayoutPriorityRequired 76 | # define ALLayoutPriorityDefaultHigh UILayoutPriorityDefaultHigh 77 | # define ALLayoutPriorityDefaultLow UILayoutPriorityDefaultLow 78 | # define ALLayoutPriorityFittingSizeLevel UILayoutPriorityFittingSizeLevel 79 | # define ALLayoutPriorityFittingSizeCompression ALLayoutPriorityFittingSizeLevel 80 | #else 81 | # import 82 | # define ALView NSView 83 | # define ALEdgeInsets NSEdgeInsets 84 | # define ALEdgeInsetsZero NSEdgeInsetsMake(0, 0, 0, 0) 85 | # define ALEdgeInsetsMake NSEdgeInsetsMake 86 | # define ALLayoutConstraintOrientation NSLayoutConstraintOrientation 87 | # define ALLayoutConstraintAxis ALLayoutConstraintOrientation 88 | # define ALLayoutConstraintOrientationHorizontal NSLayoutConstraintOrientationHorizontal 89 | # define ALLayoutConstraintOrientationVertical NSLayoutConstraintOrientationVertical 90 | # define ALLayoutConstraintAxisHorizontal ALLayoutConstraintOrientationHorizontal 91 | # define ALLayoutConstraintAxisVertical ALLayoutConstraintOrientationVertical 92 | # define ALLayoutPriority NSLayoutPriority 93 | # define ALLayoutPriorityRequired NSLayoutPriorityRequired 94 | # define ALLayoutPriorityDefaultHigh NSLayoutPriorityDefaultHigh 95 | # define ALLayoutPriorityDefaultLow NSLayoutPriorityDefaultLow 96 | # define ALLayoutPriorityFittingSizeCompression NSLayoutPriorityFittingSizeCompression 97 | # define ALLayoutPriorityFittingSizeLevel ALLayoutPriorityFittingSizeCompression 98 | #endif /* TARGET_OS_IPHONE */ 99 | 100 | 101 | #pragma mark PureLayout Attributes 102 | 103 | /** Constants that represent edges of a view. */ 104 | typedef NS_ENUM(NSInteger, ALEdge) { 105 | /** The left edge of the view. */ 106 | ALEdgeLeft = NSLayoutAttributeLeft, 107 | /** The right edge of the view. */ 108 | ALEdgeRight = NSLayoutAttributeRight, 109 | /** The top edge of the view. */ 110 | ALEdgeTop = NSLayoutAttributeTop, 111 | /** The bottom edge of the view. */ 112 | ALEdgeBottom = NSLayoutAttributeBottom, 113 | /** The leading edge of the view (left edge for left-to-right languages like English, right edge for right-to-left languages like Arabic). */ 114 | ALEdgeLeading = NSLayoutAttributeLeading, 115 | /** The trailing edge of the view (right edge for left-to-right languages like English, left edge for right-to-left languages like Arabic). */ 116 | ALEdgeTrailing = NSLayoutAttributeTrailing 117 | }; 118 | 119 | /** Constants that represent dimensions of a view. */ 120 | typedef NS_ENUM(NSInteger, ALDimension) { 121 | /** The width of the view. */ 122 | ALDimensionWidth = NSLayoutAttributeWidth, 123 | /** The height of the view. */ 124 | ALDimensionHeight = NSLayoutAttributeHeight 125 | }; 126 | 127 | /** Constants that represent axes of a view. */ 128 | typedef NS_ENUM(NSInteger, ALAxis) { 129 | /** A vertical line equidistant from the view's left and right edges. */ 130 | ALAxisVertical = NSLayoutAttributeCenterX, 131 | /** A horizontal line equidistant from the view's top and bottom edges. */ 132 | ALAxisHorizontal = NSLayoutAttributeCenterY, 133 | 134 | /** A horizontal line at the baseline of the last line of text in the view. (For views that do not draw text, will be equivalent to ALEdgeBottom.) Same as ALAxisLastBaseline. */ 135 | ALAxisBaseline = NSLayoutAttributeBaseline, 136 | /** A horizontal line at the baseline of the last line of text in the view. (For views that do not draw text, will be equivalent to ALEdgeBottom.) */ 137 | ALAxisLastBaseline = ALAxisBaseline, 138 | #if __PureLayout_MinBaseSDK_iOS_8_0 139 | /** A horizontal line at the baseline of the first line of text in a view. (For views that do not draw text, will be equivalent to ALEdgeTop.) Available in iOS 8.0 and later. */ 140 | ALAxisFirstBaseline = NSLayoutAttributeFirstBaseline 141 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 */ 142 | }; 143 | 144 | #if __PureLayout_MinBaseSDK_iOS_8_0 145 | 146 | /** Constants that represent layout margins of a view. Available in iOS 8.0 and later. */ 147 | typedef NS_ENUM(NSInteger, ALMargin) { 148 | /** The left margin of the view, based on the view's layoutMargins left inset. */ 149 | ALMarginLeft = NSLayoutAttributeLeftMargin, 150 | /** The right margin of the view, based on the view's layoutMargins right inset. */ 151 | ALMarginRight = NSLayoutAttributeRightMargin, 152 | /** The top margin of the view, based on the view's layoutMargins top inset. */ 153 | ALMarginTop = NSLayoutAttributeTopMargin, 154 | /** The bottom margin of the view, based on the view's layoutMargins bottom inset. */ 155 | ALMarginBottom = NSLayoutAttributeBottomMargin, 156 | /** The leading margin of the view, based on the view's layoutMargins left/right (depending on language direction) inset. */ 157 | ALMarginLeading = NSLayoutAttributeLeadingMargin, 158 | /** The trailing margin of the view, based on the view's layoutMargins left/right (depending on language direction) inset. */ 159 | ALMarginTrailing = NSLayoutAttributeTrailingMargin 160 | }; 161 | 162 | /** Constants that represent axes of the layout margins of a view. Available in iOS 8.0 and later. */ 163 | typedef NS_ENUM(NSInteger, ALMarginAxis) { 164 | /** A vertical line equidistant from the view's left and right margins. */ 165 | ALMarginAxisVertical = NSLayoutAttributeCenterXWithinMargins, 166 | /** A horizontal line equidistant from the view's top and bottom margins. */ 167 | ALMarginAxisHorizontal = NSLayoutAttributeCenterYWithinMargins 168 | }; 169 | 170 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 */ 171 | 172 | /** An attribute of a view that can be used in auto layout constraints. These constants are identical to the more specific enum types: 173 | ALEdge, ALAxis, ALDimension, ALMargin, ALMarginAxis. It is safe to cast a more specific enum type to the ALAttribute type. */ 174 | typedef NS_ENUM(NSInteger, ALAttribute) { 175 | /** The left edge of the view. */ 176 | ALAttributeLeft = ALEdgeLeft, 177 | /** The right edge of the view. */ 178 | ALAttributeRight = ALEdgeRight, 179 | /** The top edge of the view. */ 180 | ALAttributeTop = ALEdgeTop, 181 | /** The bottom edge of the view. */ 182 | ALAttributeBottom = ALEdgeBottom, 183 | /** The leading edge of the view (left edge for left-to-right languages like English, right edge for right-to-left languages like Arabic). */ 184 | ALAttributeLeading = ALEdgeLeading, 185 | /** The trailing edge of the view (right edge for left-to-right languages like English, left edge for right-to-left languages like Arabic). */ 186 | ALAttributeTrailing = ALEdgeTrailing, 187 | /** The width of the view. */ 188 | ALAttributeWidth = ALDimensionWidth, 189 | /** The height of the view. */ 190 | ALAttributeHeight = ALDimensionHeight, 191 | /** A vertical line equidistant from the view's left and right edges. */ 192 | ALAttributeVertical = ALAxisVertical, 193 | /** A horizontal line equidistant from the view's top and bottom edges. */ 194 | ALAttributeHorizontal = ALAxisHorizontal, 195 | /** A horizontal line at the baseline of the last line of text in the view. (For views that do not draw text, will be equivalent to ALEdgeBottom.) Same as ALAxisLastBaseline. */ 196 | ALAttributeBaseline = ALAxisBaseline, 197 | /** A horizontal line at the baseline of the last line of text in the view. (For views that do not draw text, will be equivalent to ALEdgeBottom.) */ 198 | ALAttributeLastBaseline = ALAxisLastBaseline, 199 | #if __PureLayout_MinBaseSDK_iOS_8_0 200 | /** A horizontal line at the baseline of the first line of text in a view. (For views that do not draw text, will be equivalent to ALEdgeTop.) Available in iOS 8.0 and later. */ 201 | ALAttributeFirstBaseline = ALAxisFirstBaseline, 202 | /** The left margin of the view, based on the view's layoutMargins left inset. */ 203 | ALAttributeMarginLeft = ALMarginLeft, 204 | /** The right margin of the view, based on the view's layoutMargins right inset. */ 205 | ALAttributeMarginRight = ALMarginRight, 206 | /** The top margin of the view, based on the view's layoutMargins top inset. */ 207 | ALAttributeMarginTop = ALMarginTop, 208 | /** The bottom margin of the view, based on the view's layoutMargins bottom inset. */ 209 | ALAttributeMarginBottom = ALMarginBottom, 210 | /** The leading margin of the view, based on the view's layoutMargins left/right (depending on language direction) inset. */ 211 | ALAttributeMarginLeading = ALMarginLeading, 212 | /** The trailing margin of the view, based on the view's layoutMargins left/right (depending on language direction) inset. */ 213 | ALAttributeMarginTrailing = ALMarginTrailing, 214 | /** A vertical line equidistant from the view's left and right margins. */ 215 | ALAttributeMarginAxisVertical = ALMarginAxisVertical, 216 | /** A horizontal line equidistant from the view's top and bottom margins. */ 217 | ALAttributeMarginAxisHorizontal = ALMarginAxisHorizontal 218 | #endif /* __PureLayout_MinBaseSDK_iOS_8_0 */ 219 | }; 220 | 221 | /** A block containing method calls to the PureLayout API. Takes no arguments and has no return value. */ 222 | typedef void(^ALConstraintsBlock)(void); 223 | 224 | #endif /* PureLayoutDefines_h */ 225 | -------------------------------------------------------------------------------- /XTrello/View Classes/XTTagView.h: -------------------------------------------------------------------------------- 1 | // 2 | // XTTagView.h 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/11/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface XTTagView : NSView 12 | 13 | @property (nonatomic, strong) NSColor *backgroundColor; 14 | - (id)initWithFrame:(NSRect)frame andColor:(NSColor *)bgColor; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /XTrello/View Classes/XTTagView.m: -------------------------------------------------------------------------------- 1 | // 2 | // XTTagView.m 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/11/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import "XTTagView.h" 10 | 11 | @implementation XTTagView 12 | 13 | - (id)initWithFrame:(NSRect)frame andColor:(NSColor *)bgColor 14 | { 15 | self = [super initWithFrame:frame]; 16 | if (self) { 17 | // Initialization code here. 18 | self.backgroundColor = bgColor; 19 | 20 | } 21 | return self; 22 | } 23 | 24 | - (void)drawRect:(NSRect)dirtyRect 25 | { 26 | // NSLog(@"drawRect"); 27 | [[self backgroundColor] setFill]; 28 | NSRectFill(dirtyRect); 29 | [super drawRect:dirtyRect]; 30 | 31 | } 32 | 33 | - (NSString *)description 34 | { 35 | NSString *desc = [super description]; 36 | return [NSString stringWithFormat:@"%@ %@", desc, NSStringFromRect(self.frame)]; 37 | 38 | } 39 | 40 | /* 41 | 42 | 43 | if ([[theLabel lowercaseString] isEqualToString:@"bug"]) colorString = @"red"; 44 | if ([[theLabel lowercaseString] isEqualToString:@"testing"]) colorString = @"purple"; 45 | if ([[theLabel lowercaseString] isEqualToString:@"feature"]) colorString = @"blue"; 46 | 47 | */ 48 | 49 | 50 | //40x4 51 | 52 | //6*44 53 | //264 max size? 54 | 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /XTrello/View Classes/XTTagViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XTTagViewController.h 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/11/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "XTTagView.h" 11 | 12 | @interface XTTagViewController : NSView 13 | 14 | @property (nonatomic, strong) NSArray *labels; 15 | 16 | - (id)initWithFrame:(NSRect)frame andLabels:(NSArray *)labelArray; 17 | 18 | - (void)updateLabels:(NSArray *)theLabels; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /XTrello/View Classes/XTTagViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XTTagViewController.m 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/11/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import "XTTagViewController.h" 10 | 11 | @implementation XTTagViewController 12 | 13 | - (id)initWithFrame:(NSRect)frame andLabels:(NSArray *)labelArray 14 | { 15 | self = [super initWithFrame:frame]; 16 | if (self) { 17 | // Initialization code here. 18 | float offset = 0; 19 | float tagSize = 40; 20 | if (labelArray.count > 6) 21 | { 22 | tagSize = (264 / labelArray.count) - 4; 23 | 24 | } 25 | for (NSString *colorString in labelArray) 26 | { 27 | NSColor *newColor = [self colorFromString:colorString]; 28 | NSRect viewRect = NSMakeRect(offset, 0, tagSize, 10); 29 | XTTagView *newView = [[XTTagView alloc] initWithFrame:viewRect andColor:newColor]; 30 | // NSView *newView = [[NSView alloc] initWithFrame:viewRect]; 31 | [self addSubview:newView]; 32 | offset = offset + (tagSize + 4); 33 | } 34 | } 35 | return self; 36 | } 37 | 38 | - (NSColor *)colorFromString:(NSString *)theString 39 | { 40 | if ([theString isEqualToString:@"green"]) return [NSColor greenColor]; 41 | if ([theString isEqualToString:@"yellow"]) return [NSColor yellowColor]; 42 | if ([theString isEqualToString:@"orange"]) return [NSColor orangeColor]; 43 | if ([theString isEqualToString:@"red"]) return [NSColor redColor]; 44 | if ([theString isEqualToString:@"purple"]) return [NSColor purpleColor]; 45 | if ([theString isEqualToString:@"blue"]) return [NSColor blueColor]; 46 | if ([theString isEqualToString:@"pink"]) return [NSColor pinkColor]; 47 | if ([theString isEqualToString:@"sky"]) return [NSColor skyColor]; 48 | if ([theString isEqualToString:@"lime"]) return [NSColor limeColor]; 49 | return nil; 50 | } 51 | 52 | - (void)removeAllSubviews 53 | { 54 | NSArray *subviews = [self subviews]; 55 | int i = 0; 56 | for (i = 0; i < subviews.count; i++) { 57 | 58 | NSView *theView = [subviews objectAtIndex:i]; 59 | [theView removeFromSuperview]; 60 | 61 | } 62 | } 63 | 64 | - (NSArray *)reuseSubviews:(NSArray *)inputArray 65 | { 66 | NSMutableArray *returnArray = [inputArray mutableCopy]; 67 | int currentIndex = 0; 68 | for (XTTagView *theView in self.subviews) 69 | { 70 | NSString *colorString = [returnArray objectAtIndex:currentIndex]; 71 | theView.backgroundColor = [self colorFromString:colorString]; 72 | [returnArray removeObject:colorString]; 73 | } 74 | return returnArray; 75 | } 76 | 77 | - (void)updateLabels:(NSArray *)theLabels 78 | { 79 | [self removeAllSubviews]; 80 | float offset = 0; 81 | int currentLabel = 0; 82 | float currentY = 0; 83 | // if (finalArray.count != theLabels.count) 84 | // { 85 | // //update the offset 86 | // // NSInteger arrayDiff = theLabels.count - finalArray.count; 87 | // offset = 44 * (finalArray.count+1); 88 | // NSLog(@"finalArray.count: %li offset: %f", finalArray.count, offset); 89 | // } 90 | for (NSString *colorString in theLabels) 91 | { 92 | NSLog(@"currentLabel: %i", currentLabel); 93 | if (currentLabel == 7) 94 | { 95 | currentY = 22; 96 | offset = 0; 97 | } 98 | NSColor *newColor = [self colorFromString:colorString]; 99 | NSRect viewRect = NSMakeRect(offset, currentY, 40, 10); 100 | 101 | XTTagView *newView = [[XTTagView alloc] initWithFrame:viewRect andColor:newColor]; 102 | [self addSubview:newView]; 103 | offset = offset + 44; 104 | currentLabel++; 105 | } 106 | [self setNeedsDisplay:TRUE]; 107 | } 108 | 109 | //- (void)drawRect:(NSRect)dirtyRect 110 | //{ 111 | // [super drawRect:dirtyRect]; 112 | // 113 | // // Drawing code here. 114 | //} 115 | 116 | @end 117 | -------------------------------------------------------------------------------- /XTrello/View Classes/XTTrelloCardView.h: -------------------------------------------------------------------------------- 1 | // 2 | // XTTrelloCardView.h 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/10/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "XTTagView.h" 11 | #import "XTTagViewController.h" 12 | 13 | @protocol XTTrelloCardViewDelegate; 14 | 15 | @interface XTTrelloCardView : NSTableCellView 16 | { 17 | XTTagView *_dividerView; 18 | NSMenu *context; 19 | NSMenu *listsMenu; 20 | NSMenu *memberListMenu; 21 | NSMenu *boardsMenu; 22 | } 23 | @property (nonatomic, weak) IBOutlet NSTextField *titleView; 24 | @property (nonatomic, strong) XTTagViewController *tagViewController; 25 | @property (nonatomic, strong) NSDictionary *cardDict; 26 | @property (nonatomic, strong) NSString *boardName; 27 | @property (nonatomic, strong) NSString *listName; 28 | @property (nonatomic, weak) id delegate; 29 | - (IBAction)moveCard:(id)sender; 30 | - (IBAction)deleteCard:(id)sender; 31 | - (IBAction)setCardLabels:(id)sender; 32 | 33 | - (void)editText; 34 | - (IBAction)textfieldDidEndEditing:(NSTextField *)sender; 35 | - (void)setLabels:(NSArray *)theLabel; 36 | - (void)mouseDownForTextFields:(NSEvent *)theEvent; 37 | - (void)setupView; 38 | - (BOOL)containsLabel:(NSString *)labelName; 39 | @end 40 | 41 | @protocol XTTrelloCardViewDelegate 42 | 43 | - (NSArray *)boardNames; 44 | - (NSArray *)boardArray; 45 | - (void)jumpToCode:(NSDictionary *)codeDict; 46 | - (void)populateCardsFromListNamed:(NSString *)listName inBoard:(NSString *)boardName; 47 | - (void)addNewCard:(id)sender; 48 | @end -------------------------------------------------------------------------------- /XTrello/View Classes/XTTrelloCardView.m: -------------------------------------------------------------------------------- 1 | // 2 | // XTTrelloCardView.m 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/10/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import "XTTrelloCardView.h" 10 | #import "XTTrelloWrapper.h" 11 | #import "XTTagView.h" 12 | #import "NSMenuItem+boardDict.h" 13 | 14 | @implementation XTTrelloCardView 15 | 16 | - (id)initWithFrame:(NSRect)frame 17 | { 18 | self = [super initWithFrame:frame]; 19 | if (self) { 20 | 21 | } 22 | return self; 23 | } 24 | 25 | - (void)showDeleteCardAlert 26 | { 27 | NSAlert *deleteAlert = [NSAlert alertWithMessageText:@"Deletion Warning" defaultButton:@"Delete" alternateButton:@"Cancel" otherButton:nil informativeTextWithFormat:@"Are you sure you want to delete the card: %@? This cannot be undone!!", self.cardDict[@"name"]]; 28 | 29 | NSModalResponse deleteResponse = [deleteAlert runModal]; 30 | switch (deleteResponse) { 31 | 32 | case NSAlertDefaultReturn: 33 | 34 | [[XTTrelloWrapper sharedInstance] deleteCard:self.cardDict inBoardNamed:self.boardName]; 35 | [self delegateRefreshList]; 36 | break; 37 | 38 | case NSAlertAlternateReturn: 39 | 40 | break; 41 | } 42 | } 43 | 44 | 45 | - (IBAction)textfieldDidEndEditing:(NSTextField *)sender 46 | { 47 | if (![[sender stringValue] isEqualToString:self.cardDict[@"name"]]) 48 | { 49 | NSString *cardName = [sender stringValue]; 50 | NSDictionary *boardDict = [[[[XTTrelloWrapper sharedInstance] updateLocalCard:self.cardDict withName:sender.stringValue inBoardNamed:self.boardName] objectForKey:@"boards"] objectForKey:self.boardName]; 51 | NSDictionary *cardSearch = [[[boardDict objectForKey:@"cards"] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"(SELF.name == %@)", sender.stringValue]] lastObject]; 52 | self.cardDict = cardSearch; 53 | 54 | CGRect nameFrame = sender.frame; 55 | NSFont *labelFont = [NSFont systemFontOfSize:12]; 56 | CGFloat cardNameHeight = [cardName heightForStringWithFont:labelFont withWidth:280] + 10; 57 | CGFloat cardNameOriginY = (100.0 - cardNameHeight)/2; 58 | nameFrame.size.height = cardNameHeight; 59 | nameFrame.origin.y = cardNameOriginY; 60 | nameFrame.size.width = 290; 61 | sender.frame = nameFrame; 62 | } 63 | [sender setEditable:FALSE]; 64 | [sender setBordered:FALSE]; 65 | [sender resignFirstResponder]; 66 | } 67 | 68 | - (void)editText 69 | { 70 | [self.titleView setEditable:TRUE]; 71 | [self.titleView setBordered:TRUE]; 72 | [[self window] makeFirstResponder:self.titleView]; 73 | } 74 | 75 | - (void)moveCardToBoard:(NSMenuItem *)sender 76 | { 77 | XTTrelloWrapper *apiWrapper = [XTTrelloWrapper sharedInstance]; 78 | NSDictionary *boardDict = sender.boardDictionary; 79 | //NSLog(@"boardDict; %@", boardDict); 80 | //return; 81 | NSString *newBoardName = boardDict[@"boardName"]; 82 | NSString *chosenListName = boardDict[@"listName"]; 83 | 84 | NSLog(@"cardDict: %@", self.cardDict); 85 | [apiWrapper moveCard:self.cardDict fromBoardNamed:self.boardName toBoardNamed:newBoardName toListNamed:chosenListName]; 86 | //[apiWrapper moveCard:self.cardDict toListWithID:listID inBoardNamed:self.boardName]; 87 | [self delegateRefreshList]; 88 | 89 | } 90 | 91 | - (IBAction)moveCard:(id)sender 92 | { 93 | XTTrelloWrapper *apiWrapper = [XTTrelloWrapper sharedInstance]; 94 | NSString *listName = [sender title]; 95 | NSString *listID = [[apiWrapper listWithName:listName inBoardNamed:self.boardName] valueForKey:@"id"]; 96 | [apiWrapper moveCard:self.cardDict toListWithID:listID inBoardNamed:self.boardName]; 97 | [self delegateRefreshList]; 98 | } 99 | 100 | - (IBAction)deleteCard:(id)sender 101 | { 102 | [self showDeleteCardAlert]; 103 | } 104 | 105 | - (NSArray *)usefulLabelArray:(NSArray *)labelArray 106 | { 107 | NSMutableArray *newArray = [[NSMutableArray alloc] init]; 108 | for (NSDictionary *labelDict in labelArray) 109 | { 110 | [newArray addObject:labelDict[@"color"]]; 111 | } 112 | return newArray; 113 | } 114 | 115 | - (void)delegateRefreshList 116 | { 117 | [self.delegate populateCardsFromListNamed:self.listName inBoard:self.boardName]; 118 | 119 | } 120 | 121 | //1 = on, 0 = off 122 | - (IBAction)setCardLabels:(id)sender 123 | { 124 | XTMenuItem *menuItem = (XTMenuItem *)sender; 125 | NSString *realValue = [menuItem realValue]; 126 | NSInteger state = menuItem.state; 127 | if (state == 0) //it was off and that particular label didnt exist yet 128 | { 129 | NSMutableArray *currentLabels = [[[self cardDict] valueForKey:@"labels"] mutableCopy]; 130 | // NSDictionary *newLabel = @{@"color": realValue, @"name": menuItem.title}; 131 | 132 | NSDictionary *newLabel = [[XTTrelloWrapper sharedInstance] labelDictionaryFromColor:realValue inBoardNamed:self.boardName]; 133 | 134 | NSLog(@"newLabel: %@", newLabel); 135 | 136 | [currentLabels addObject:newLabel]; 137 | 138 | 139 | 140 | [[XTTrelloWrapper sharedInstance] updateLocalCardLabels:self.cardDict withList:currentLabels inBoardNamed:self.boardName]; 141 | [[XTTrelloWrapper sharedInstance] addLabelID:newLabel[@"id"] forCardWithID:self.cardDict[@"id"]]; 142 | 143 | 144 | } else { //delete the label! 145 | 146 | NSMutableArray *currentLabels = [[[self cardDict] valueForKey:@"labels"] mutableCopy]; 147 | NSDictionary *newLabel = [[XTTrelloWrapper sharedInstance] labelDictionaryFromColor:realValue inBoardNamed:self.boardName]; 148 | // NSDictionary *newLabel = @{@"color": realValue, @"name": menuItem.title}; 149 | [currentLabels removeObject:newLabel]; 150 | [[XTTrelloWrapper sharedInstance] updateLocalCardLabels:self.cardDict withList:currentLabels inBoardNamed:self.boardName]; 151 | [[XTTrelloWrapper sharedInstance] deleteLabelID:newLabel[@"id"] forCardWithID:self.cardDict[@"id"]]; 152 | } 153 | 154 | if (state == 0) state = 1; 155 | if (state == 1) state = 0; 156 | [menuItem setState:state]; 157 | 158 | [self delegateRefreshList]; 159 | 160 | } 161 | 162 | - (BOOL)containsMemberId:(NSString *)memberID 163 | { 164 | return [[[self cardDict] valueForKey:@"idMembers"] containsObject:memberID]; 165 | } 166 | 167 | 168 | - (BOOL)containsMember:(NSString *)memberName 169 | { 170 | BOOL containsBool = FALSE; 171 | 172 | NSDictionary *cardSearch = [[[[self cardDict] valueForKey:@"members"] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"(fullName == %@)",memberName]] lastObject]; 173 | if (cardSearch != nil) 174 | containsBool = TRUE; 175 | else 176 | containsBool = FALSE; 177 | 178 | 179 | return containsBool; 180 | 181 | } 182 | 183 | - (BOOL)containsLabel:(NSString *)labelName 184 | { 185 | BOOL containsBool = FALSE; 186 | 187 | NSDictionary *cardSearch = [[[[self cardDict] valueForKey:@"labels"] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"(color == %@)",labelName]] lastObject]; 188 | if (cardSearch != nil) 189 | containsBool = TRUE; 190 | else 191 | containsBool = FALSE; 192 | 193 | 194 | return containsBool; 195 | 196 | } 197 | 198 | - (void)populateLists 199 | { 200 | if ([[listsMenu itemArray] count] == 0) 201 | { 202 | NSArray *listsObjects = [[[XTTrelloWrapper sharedInstance] boardNamed:self.boardName] objectForKey:@"lists"]; 203 | int itemTag = 0; 204 | for (NSDictionary *currentList in listsObjects) 205 | { 206 | NSString *listName = currentList[@"name"]; 207 | NSMenuItem *currentItem = [[NSMenuItem alloc] initWithTitle:listName action:@selector(moveCard:) keyEquivalent:@""]; 208 | [currentItem setTag:itemTag]; 209 | itemTag++; 210 | [listsMenu addItem:currentItem]; 211 | } 212 | } 213 | 214 | if ([[boardsMenu itemArray] count] == 0) 215 | { 216 | NSArray *boardObjects = [self.delegate boardArray]; 217 | int itemTag = 0; 218 | for (NSDictionary *currentBoard in boardObjects) 219 | { 220 | NSMenuItem *currentItem = [[NSMenuItem alloc] initWithTitle:currentBoard[@"name"] action:@selector(moveCardToBoard:) keyEquivalent:@""]; 221 | 222 | NSMenu *listsSubmenu = [[NSMenu alloc] initWithTitle:@""]; 223 | 224 | for (NSDictionary *list in currentBoard[@"lists"]) 225 | { 226 | 227 | NSMenuItem *currentSubItem = [[NSMenuItem alloc] initWithTitle:list[@"name"] action:@selector(moveCardToBoard:) keyEquivalent:@""]; 228 | currentSubItem.boardDictionary = @{@"boardName": currentBoard[@"name"], @"listName": list[@"name"]}; 229 | [listsSubmenu addItem:currentSubItem]; 230 | } 231 | 232 | [currentItem setTag:itemTag]; 233 | itemTag++; 234 | [currentItem setSubmenu:listsSubmenu]; 235 | [boardsMenu addItem:currentItem]; 236 | } 237 | } 238 | 239 | /* 240 | if ([[boardsMenu itemArray] count] == 0) 241 | { 242 | NSArray *boardObjects = [self.delegate boardNames]; 243 | int itemTag = 0; 244 | for (NSString *currentBoard in boardObjects) 245 | { 246 | NSMenuItem *currentItem = [[NSMenuItem alloc] initWithTitle:currentBoard action:@selector(moveCardToBoard:) keyEquivalent:@""]; 247 | [currentItem setTag:itemTag]; 248 | itemTag++; 249 | [boardsMenu addItem:currentItem]; 250 | } 251 | } 252 | */ 253 | } 254 | 255 | - (void)setCardMember:(id)sender 256 | { 257 | XTMenuItem *menuItem = (XTMenuItem *)sender; 258 | NSString *realValue = [menuItem realValue]; 259 | NSInteger state = menuItem.state; 260 | if (state == 0) 261 | { 262 | NSMutableArray *currentLabels = [[[self cardDict] valueForKey:@"idMembers"] mutableCopy]; 263 | [currentLabels addObject:realValue]; 264 | 265 | [[XTTrelloWrapper sharedInstance] addMemberId:realValue toCard:self.cardDict inBoardNamed:self.boardName]; 266 | 267 | } else { 268 | 269 | NSMutableArray *currentLabels = [[[self cardDict] valueForKey:@"labels"] mutableCopy]; 270 | [currentLabels removeObject:realValue]; 271 | 272 | [[XTTrelloWrapper sharedInstance] removeMemberId:realValue fromCard:self.cardDict inBoardNamed:self.boardName]; 273 | } 274 | 275 | if (state == 0) state = 1; 276 | if (state == 1) state = 0; 277 | [menuItem setState:state]; 278 | 279 | [self delegateRefreshList]; 280 | 281 | } 282 | 283 | - (NSMenu *)memberSubmenu 284 | { 285 | NSMenu *membersSubmenu = [[NSMenu alloc] initWithTitle:@""]; 286 | NSArray *memberArray = [[[XTTrelloWrapper sharedInstance] boardNamed:self.boardName] valueForKey:@"members"]; 287 | for (NSDictionary *currentMember in memberArray) 288 | { 289 | 290 | XTMenuItem *memberMenuItem = [[XTMenuItem alloc] initWithTitle:currentMember[@"fullName"] action:@selector(setCardMember:) keyEquivalent:@""]; 291 | 292 | [memberMenuItem setRealValue:currentMember[@"id"]]; 293 | 294 | if ([self containsMemberId:currentMember[@"id"]]) 295 | { 296 | [memberMenuItem setState:1]; 297 | } 298 | [membersSubmenu addItem:memberMenuItem]; 299 | 300 | } 301 | return membersSubmenu; 302 | 303 | } 304 | 305 | 306 | - (NSMenu *)colorSubmenu 307 | { 308 | NSMenu *labelsSubmenu = [[NSMenu alloc] initWithTitle:@""]; 309 | // NSDictionary *labelArray = [[[XTTrelloWrapper sharedInstance] boardNamed:self.boardName] valueForKey:@"labelNames"]; 310 | NSArray *labelArray = [[[XTTrelloWrapper sharedInstance] boardNamed:self.boardName] valueForKey:@"labels"]; 311 | // NSLog(@"### labelArray: %@", labelArray); 312 | NSEnumerator *colorEnum = [labelArray objectEnumerator]; 313 | id theColor = nil; 314 | int labelTag = 0; 315 | while(theColor = [colorEnum nextObject]) 316 | { 317 | NSString *currentColor = theColor[@"color"]; 318 | NSMutableDictionary *attrs = [[NSMutableDictionary alloc] init]; 319 | NSColor *ourColor = [currentColor colorFromName]; 320 | if (ourColor != nil) 321 | [attrs setObject:[currentColor colorFromName] forKey:NSForegroundColorAttributeName]; 322 | else 323 | NSLog(@"why is this color nil??: %@", theColor); 324 | [attrs setObject:[NSColor blackColor] forKey:NSStrokeColorAttributeName]; 325 | [attrs setObject:[NSString stringWithFormat:@"%f", -3.0f] forKey:NSStrokeWidthAttributeName]; 326 | [attrs setObject:[NSFont menuFontOfSize:14] forKey:NSFontAttributeName]; 327 | NSString *labelNamePlain = theColor[@"name"]; 328 | // NSString *labelNamePlain = [labelArray objectForKey:theColor]; 329 | if (labelNamePlain.length == 0) 330 | { 331 | labelNamePlain = currentColor; 332 | } 333 | NSAttributedString *labelName = [[NSAttributedString alloc] initWithString:labelNamePlain attributes:attrs]; 334 | XTMenuItem *currentLabel = [[XTMenuItem alloc] init]; 335 | [currentLabel setAttributedTitle:labelName]; 336 | [currentLabel setAction:@selector(setCardLabels:)]; 337 | [currentLabel setRealValue:currentColor]; 338 | [currentLabel setTag:labelTag]; 339 | if ([self containsLabel:currentColor]) 340 | { 341 | [currentLabel setState:1]; 342 | } 343 | [labelsSubmenu addItem:currentLabel]; 344 | labelTag++; 345 | } 346 | return labelsSubmenu; 347 | 348 | } 349 | 350 | - (void)jumpToCode:(id)sender 351 | { 352 | [[self delegate] jumpToCode:self.cardDict]; 353 | } 354 | 355 | - (void)setupMenu 356 | { 357 | context = [[NSMenu alloc] initWithTitle:@""]; 358 | listsMenu = [[NSMenu alloc] initWithTitle:@""]; 359 | boardsMenu = [[NSMenu alloc] initWithTitle:@""]; 360 | NSMenuItem *setLabelsMenu = [[NSMenuItem alloc] initWithTitle:@"Set Labels" action:nil keyEquivalent:@""]; 361 | NSMenu *labelsSubmenu = [self colorSubmenu]; 362 | [setLabelsMenu setSubmenu:labelsSubmenu]; 363 | [context addItem:setLabelsMenu]; 364 | 365 | NSMenuItem *setMembers = [[NSMenuItem alloc] initWithTitle:@"Set Members" action:nil keyEquivalent:@""]; 366 | 367 | [setMembers setSubmenu:[self memberSubmenu]]; 368 | 369 | [context addItem:setMembers]; 370 | 371 | listsMenu = [[NSMenu alloc] initWithTitle:@""]; 372 | [self populateLists]; 373 | NSMenuItem *changeListMenu = [[NSMenuItem alloc] initWithTitle:@"Move to List" action:nil keyEquivalent:@""]; 374 | [changeListMenu setSubmenu:listsMenu]; 375 | [context addItem:changeListMenu]; 376 | 377 | NSMenuItem *changeBoardMenu = [[NSMenuItem alloc] initWithTitle:@"Move to Board" action:nil keyEquivalent:@""]; 378 | [changeBoardMenu setSubmenu:boardsMenu]; 379 | [context addItem:changeBoardMenu]; 380 | 381 | 382 | NSMenuItem *jumpToCode = [[NSMenuItem alloc] initWithTitle:@"Jump to code..." action:@selector(jumpToCode:) keyEquivalent:@""]; 383 | [context addItem:jumpToCode]; 384 | 385 | NSMenuItem *addCardItem = [[NSMenuItem alloc] initWithTitle:@"Add Card..." action:@selector(addCard:) keyEquivalent:@""]; 386 | [context addItem:addCardItem]; 387 | 388 | NSMenuItem *deleteCardItem = [[NSMenuItem alloc] initWithTitle:@"Delete Card..." action:@selector(deleteCard:) keyEquivalent:@""]; 389 | [context addItem:deleteCardItem]; 390 | 391 | NSMenuItem *commitHistoryItem = [[NSMenuItem alloc] initWithTitle:@"Set description to todays commit history..." action:@selector(setCardDescriptionToCommitLog:) keyEquivalent:@""]; 392 | [context addItem:commitHistoryItem]; 393 | 394 | 395 | } 396 | 397 | - (void)setCardDescriptionToCommitLog:(id)sender 398 | { 399 | NSString *currentDesc = self.cardDict[@"desc"]; 400 | 401 | NSString *desc = [XTModel todaysEntriesTrelloDescriptionExcludingDescription:currentDesc]; 402 | NSLog(@"#### cardDict: %@", self.cardDict); 403 | if (desc.length > 0){ 404 | 405 | [[XTTrelloWrapper sharedInstance] setDescription:desc forCardNamed:self.cardDict[@"name"] inBoardNamed:self.boardName]; 406 | } else { 407 | NSLog(@"don't overwrite stuff, nothing new to add"); 408 | } 409 | } 410 | 411 | - (void)addCard:(id)sender 412 | { 413 | [[self delegate] addNewCard:self]; 414 | } 415 | 416 | - (void)rightMouseDown:(NSEvent *)theEvent 417 | { 418 | [NSMenu popUpContextMenu:context withEvent:theEvent forView:self]; 419 | 420 | } 421 | 422 | // Respond to clicks within text fields only, because other clicks will be duplicates of events passed to mouseDown 423 | - (void)mouseDownForTextFields:(NSEvent *)theEvent { 424 | // If shift or command are being held, we're selecting rows, so ignore 425 | if ((NSCommandKeyMask | NSShiftKeyMask) & [theEvent modifierFlags]) return; 426 | if ( NSControlKeyMask & [theEvent modifierFlags]) 427 | { 428 | [self rightMouseDown:theEvent]; 429 | return; 430 | } 431 | 432 | NSPoint selfPoint = [self convertPoint:theEvent.locationInWindow fromView:nil]; 433 | for (NSView *subview in [self subviews]) 434 | { 435 | if ([subview isKindOfClass:[NSTextField class]]) 436 | { 437 | if (NSPointInRect(selfPoint, [subview frame])) 438 | { 439 | [(NSTextField *)subview setEditable:TRUE]; 440 | [(NSTextField *)subview setBordered:TRUE]; 441 | [[self window] makeFirstResponder:subview]; 442 | 443 | } 444 | } 445 | } 446 | } 447 | 448 | - (void)setupView 449 | { 450 | if (_dividerView != nil) 451 | { 452 | [_dividerView removeFromSuperview]; 453 | _dividerView = nil; 454 | } 455 | 456 | 457 | NSRect listItemFrame = self.frame; 458 | listItemFrame.origin.y = 0; 459 | listItemFrame.origin.x = -5; 460 | listItemFrame.size.width = listItemFrame.size.width + 10; 461 | listItemFrame.size.height = 5; 462 | 463 | _dividerView = [[XTTagView alloc] initWithFrame:listItemFrame andColor:[NSColor lightGrayColor]]; 464 | [self addSubview:_dividerView]; 465 | 466 | [self setupMenu]; 467 | 468 | } 469 | 470 | - (void)setLabels:(NSArray *)theLabels { 471 | 472 | LOG_SELF; 473 | } 474 | 475 | @end 476 | -------------------------------------------------------------------------------- /XTrello/XTModel.h: -------------------------------------------------------------------------------- 1 | // // XTModel.h // XToDo // // Created by Travis on 13-11-28. // Copyright (c) 2013年 Plumn LLC. All rights reserved. // #import #import #import "XTProjectSetting.h" @interface DVTChoice : NSObject - (id)initWithTitle:(id)arg1 toolTip:(id)arg2 image:(id)arg3 representedObject:(id)arg4; @end @interface DVTTextDocumentLocation : NSObject @property (readonly) NSRange characterRange; @property (readonly) NSRange lineRange; @end @interface DVTTextPreferences : NSObject + (id)preferences; @property BOOL trimWhitespaceOnlyLines; @property BOOL trimTrailingWhitespace; @property BOOL useSyntaxAwareIndenting; @end @interface DVTSourceTextStorage : NSTextStorage - (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)string withUndoManager:(id)undoManager; - (NSRange)lineRangeForCharacterRange:(NSRange)range; - (NSRange)characterRangeForLineRange:(NSRange)range; - (void)indentCharacterRange:(NSRange)range undoManager:(id)undoManager; @end @interface DVTFileDataType : NSObject @property (readonly) NSString *identifier; @end @interface DVTFilePath : NSObject @property (readonly) NSURL *fileURL; @property (readonly) DVTFileDataType *fileDataTypePresumed; @end @interface IDEContainerItem : NSObject @property (readonly) DVTFilePath *resolvedFilePath; @end @interface IDEGroup : IDEContainerItem @end @interface IDEFileReference : IDEContainerItem @end @interface PBXObject : NSObject @end @interface PBXContainerItem : PBXObject @end @interface PBXReference : PBXContainerItem - (id)buildProductRelativePath; - (id)groupRelativePath; - (id)absoluteDirectory; - (id)resolvedAbsolutePath; - (id)absolutePath; - (id)path; - (id)sourceTree; - (id)groupTreeDisplayName; - (id)name; @end @interface PBXFileReference : PBXReference @end @interface Xcode3FileReference : IDEFileReference - (PBXFileReference *)fileReference; @end @interface IDENavigableItem : NSObject @property (readonly) IDENavigableItem *parentItem; @property (readonly) id representedObject; @end @interface IDEFileNavigableItem : IDENavigableItem @property (readonly) DVTFileDataType *documentType; @property (readonly) NSURL *fileURL; @end @interface IDEStructureNavigator : NSObject @property (retain) NSArray *selectedObjects; @end @interface IDENavigableItemCoordinator : NSObject - (id)structureNavigableItemForDocumentURL:(id)arg1 inWorkspace:(id)arg2 error:(id *)arg3; @end @interface IDENavigatorArea : NSObject @property NSArrayController *extensionsController; - (id)currentNavigator; @end @interface IDEWorkspaceTabController : NSObject @property (readonly) IDENavigatorArea *navigatorArea; @property(readonly) IDEWorkspaceTabController *structureEditWorkspaceTabController; @end @interface IDEDocumentController : NSDocumentController +(IDEDocumentController*)sharedDocumentController; + (id)editorDocumentForNavigableItem:(id)arg1; + (id)retainedEditorDocumentForNavigableItem:(id)arg1 error:(id *)arg2; + (void)releaseEditorDocument:(id)arg1; @end @interface IDESourceCodeDocument : NSDocument - (DVTSourceTextStorage *)textStorage; - (NSUndoManager *)undoManager; @property(readonly) NSArray *knownFileReferences; @property(readonly) NSArray *ideTopLevelStructureObjects; @end @interface IDESourceCodeComparisonEditor : NSObject @property (readonly) NSTextView *keyTextView; @property (retain) NSDocument *primaryDocument; @end @interface IDESourceCodeEditor : NSObject @property (retain) NSTextView *textView; - (IDESourceCodeDocument *)sourceCodeDocument; @end @interface IDEEditorContext : NSObject - (id)editor; // returns the current editor. If the editor is the code editor, the class is `IDESourceCodeEditor` @end @interface IDEEditorArea : NSObject - (IDEEditorContext *)lastActiveEditorContext; @end @interface IDEConsoleArea : NSObject - (IDEEditorContext *)lastActiveEditorContext; @end @interface IDEWorkspaceWindowController : NSObject @property (readonly) IDEWorkspaceTabController *activeWorkspaceTabController; - (IDEEditorArea *)editorArea; + (id)workspaceWindowControllers; @end @interface DVTMapTable : NSObject - (id)dictionaryRepresentation; @end @interface IDESourceControlProject : NSObject @property(retain) NSMutableDictionary *requiredConfigurationsDictionary; // @synthesize requiredConfigurationsDictionary=_requiredConfigurationsDictionary; @property(retain) NSMutableDictionary *repositoryRootForConfigurationDictionary; // @synthesize repositoryRootForConfigurationDictionary=_repositoryRootForConfigurationDictionary; @property(retain) NSMutableDictionary *relativeInstallPathForConfigurationDictionary; // @synthesize relativeInstallPathForConfigurationDictionary=_relativeInstallPathForConfigurationDictionary; @property(retain) NSMutableDictionary *originForConfigurationDictionary; // @synthesize originForConfigurationDictionary=_originForConfigurationDictionary; //@property(retain) DVTCustomDataSpecifier *customDataSpecifier; // @synthesize customDataSpecifier=_customDataSpecifier; @property(getter=isFavorite) BOOL favorite; // @synthesize favorite=_favorite; @property(retain) NSMutableArray *configurationsInCurrentWorkspace; // @synthesize configurationsInCurrentWorkspace=_configurationsInCurrentWorkspace; @property unsigned long long type; // @synthesize type=_type; //@property(retain) IDESourceControlWorkingCopyConfiguration *projectWCC; // @synthesize projectWCC=_projectWCC; @property(copy) NSString *relativePathToProject; // @synthesize relativePathToProject=_relativePathToProject; @property(copy) NSURL *projectURL; // @synthesize projectURL=_projectURL; @property(readonly) NSString *uniqueIdentifier; // @synthesize uniqueIdentifier=_uniqueIdentifier; @property(copy) NSString *name; // @synthesize name=_name; - (id)dictionaryRepresentation; @end @interface IDESourceControlWorkspaceMonitor : NSObject @property(retain) IDESourceControlProject *sourceControlProject; // @synthesize sourceControlProject=_sourceControlProject; @property(readonly) DVTMapTable *workspaceRootForWorkingTreeMapTable; @end @interface IDEWorkspace : NSWorkspace @property (readonly) DVTFilePath *representingFilePath; @property(readonly) NSString *representingTitle; - (id)displayName; @property(readonly) NSString *name; @property(retain) IDESourceControlWorkspaceMonitor *sourceControlWorkspaceMonitor; // @synthesize @end @interface IDEWorkspaceDocument : NSDocument @property (readonly) IDEWorkspace *workspace; @end @interface XTModel : NSObject @property (nonatomic, assign) id delegate; + (NSArray *)logEntries; + (NSString *)todaysEntriesTrelloDescriptionExcludingDescription:(NSString *)desc; + (NSString *)applicationSupportFolder; + (NSString *)boardsDataStoreFile; + (NSString *)currentProjectName; + (NSString *)currentGITBranch; + (NSArray *)returnFromGITWithArguments:(NSArray *)gitArguments; + (NSArray *)returnFromCommand:(NSString *)commandBinary withArguments:(NSArray *)commandArguments inPath:(NSString *)thePath; + (IDESourceCodeDocument *)currentSourceCodeDocument; + (IDEWorkspaceDocument *)currentWorkspaceDocument; + (IDEWorkspaceTabController*)tabController; + (IDESourceCodeEditor*)currentEditor; + (IDESourceControlWorkspaceMonitor *)sourceControlMonitor; + (NSString *)currentProjectFile; + (NSString *)currentRootPath; + (void) cleanAllTempFiles; + (NSString *) addPathSlash:(NSString *)path; + (NSString *) rootPathMacro; + (NSArray *) explandRootPathMacros:(NSArray *)paths projectPath:(NSString *)projectPath; + (NSString *) explandRootPathMacro:(NSString *)path projectPath:(NSString *)projectPath; + (NSString *) settingFilePathByProjectName:(NSString *)projectName; + (XTProjectSetting *) projectSettingByProjectName:(NSString *)projectName; + (void) saveProjectSetting:(XTProjectSetting *)projectSetting ByProjectName:(NSString *)projectName; @end extern NSString* const kNotifyProjectSettingChanged; -------------------------------------------------------------------------------- /XTrello/XTModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // XTModel.m 3 | // XToDo 4 | // 5 | // Created by Travis on 13-11-28. 6 | // Copyright (c) 2013年 Plumn LLC. All rights reserved. 7 | // 8 | 9 | #import "XTModel.h" 10 | #import 11 | 12 | //#import "XToDoPreferencesWindowController.h" 13 | 14 | #import "NSData+Split.h" 15 | #import "XTrello.h" 16 | 17 | static NSBundle *pluginBundle; 18 | 19 | //@class XTrello; 20 | @implementation XTModel 21 | 22 | + (NSString *)applicationSupportFolder 23 | { 24 | NSBundle *ourBundle = [NSBundle bundleForClass:objc_getClass("XTrello")]; 25 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); 26 | NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil; 27 | basePath = [basePath stringByAppendingPathComponent:[[ourBundle infoDictionary] objectForKey:(NSString *)kCFBundleNameKey]]; 28 | if (![[NSFileManager defaultManager] fileExistsAtPath:basePath]) 29 | [[NSFileManager defaultManager] createDirectoryAtPath:basePath withIntermediateDirectories:YES attributes:nil error:nil]; 30 | 31 | return basePath; 32 | } 33 | 34 | + (NSString *)boardsDataStoreFile 35 | { 36 | return [[self applicationSupportFolder] stringByAppendingPathComponent:@"trelloBoards.plist"]; 37 | } 38 | 39 | //currently unused, SHOULD get an nsdictionary of commit items. 40 | 41 | + (NSArray *)logEntries 42 | { 43 | 44 | // git log --pretty="%ad COMMIT_MSG: %s" --since=1.day --date=short 45 | /* 46 | 47 | will yield something that can be parsed easier, has less of a footprint, and less overhead: 48 | 49 | 50 | 2016-11-10 - expanded out all of the umbrella categories that were lazily stored in UIView+RecursiveFind into their own individual respective classes 51 | 2016-11-09 - added predicate category that could potentially help for more complex filtering in the future 52 | 2016-11-09 - refactored a slew of categories out of NSDate into their own respective files, still need to do the same to UIView+RecursiveFind next 53 | 54 | 55 | 56 | */ 57 | 58 | NSArray *commitArray = [XTModel returnFromGITWithArguments:@[@"log", @"--pretty=\"%ad COMMIT_MSG: %s\"",@"--since=1.day", @"--date=short"]]; 59 | //NSArray *logArray = [XTModel returnFromGITWithArguments:@[@"--no-pager", @"log", @"--date=short"]]; 60 | NSDateFormatter *tf = [NSDateFormatter new]; 61 | //EEE, MMM d, ''yy Wed, July 10, '96 62 | //Tue Nov 8 17:50:32 2016 63 | //@"[EEE MMM d HH:mm:ss yyyy 64 | [tf setDateFormat:@"yyyy-MM-dd"]; 65 | // return [[logArray componentsJoinedByString:@"\n"] componentsSeparatedByString:@"commit"]; 66 | // NSArray *commitArray = [[logArray componentsJoinedByString:@"\n"] componentsSeparatedByString:@"commit"]; 67 | 68 | __block NSMutableArray *finalArray = [[NSMutableArray alloc] init]; 69 | [commitArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 70 | 71 | NSMutableDictionary *commitDict = [NSMutableDictionary new]; 72 | NSArray *items = [[obj stringByReplacingOccurrencesOfString:@"\"" withString:@""] componentsSeparatedByString:@"COMMIT_MSG: "]; 73 | if ([items count] == 2) 74 | { 75 | NSString *dateString = [items[0] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 76 | NSDate *theDate = [tf dateFromString:dateString]; 77 | commitDict[@"date"] = theDate; 78 | commitDict[@"comment"] = items[1]; 79 | [finalArray addObject:commitDict]; 80 | } 81 | }]; 82 | /* 83 | [commitArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 84 | 85 | NSMutableDictionary *commitDict = [NSMutableDictionary new]; 86 | NSMutableArray *itemArray = [[obj componentsSeparatedByString:@"\n"] mutableCopy]; 87 | [itemArray removeObject:@""]; 88 | // NSLog(@"itemArray: %@ count: %lu", itemArray, itemArray.count); 89 | if (itemArray.count >= 4) 90 | { 91 | 92 | NSString *dateString = [[[itemArray[2] componentsSeparatedByString:@"Date:"] lastObject] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 93 | 94 | NSDate *theDate = [tf dateFromString:dateString]; 95 | 96 | // NSLog(@"date string: -%@- date: %@", dateString, theDate); 97 | 98 | commitDict[@"commit"] = [itemArray[0] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 99 | commitDict[@"author"] = [[[itemArray[1] componentsSeparatedByString:@":"] lastObject] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 100 | commitDict[@"date"] = theDate; 101 | commitDict[@"comment"] = [itemArray[3] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 102 | [finalArray addObject:commitDict]; 103 | 104 | } 105 | 106 | }]; 107 | */ 108 | return finalArray; 109 | } 110 | 111 | + (NSPredicate *)todayPredicate 112 | { 113 | NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 114 | NSDate *today = [NSDate date]; 115 | NSDateComponents *toDateComponents = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:today]; 116 | NSDate *beginning = [calendar dateFromComponents:toDateComponents]; 117 | return [NSPredicate predicateWithFormat:@"date >= %@ && date <= %@", beginning, today]; 118 | } 119 | 120 | 121 | + (NSString *)todaysEntriesTrelloDescriptionExcludingDescription:(NSString *)desc 122 | { 123 | NSArray *descArray = [desc componentsSeparatedByString:@"\n"]; 124 | NSArray *todayArray = [[self logEntries] filteredArrayUsingPredicate:[self todayPredicate]]; 125 | __block NSMutableString *newString = [NSMutableString new]; 126 | if (descArray.count > 0) 127 | { 128 | [newString appendFormat:@"%@\n",desc]; 129 | } 130 | [todayArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 131 | 132 | if (![descArray containsString:obj[@"comment"]]) 133 | { 134 | [newString appendFormat:@"- %@\n", obj[@"comment"]]; 135 | } else { 136 | NSLog(@"#### comment already exists!"); 137 | } 138 | 139 | 140 | }]; 141 | return newString; 142 | } 143 | 144 | 145 | + (NSString *)currentGITBranch 146 | { 147 | NSString *currentBranch = nil; 148 | NSArray *branchArray = [self returnFromGITWithArguments:[NSArray arrayWithObjects:@"branch", @"--list", nil]]; 149 | for (NSString *branchItem in branchArray) 150 | { 151 | if ([branchItem rangeOfString:@"*"].location != NSNotFound) 152 | currentBranch = [branchItem substringFromIndex:2]; 153 | } 154 | return currentBranch; 155 | } 156 | 157 | + (NSArray *)returnFromGITWithArguments:(NSArray *)gitArguments 158 | { 159 | NSString *rootPath = [XTModel currentRootPath]; 160 | return [XTModel returnFromCommand:@"/usr/bin/git" withArguments:gitArguments inPath:rootPath]; 161 | } 162 | 163 | + (NSArray *)returnFromCommand:(NSString *)commandBinary withArguments:(NSArray *)commandArguments inPath:(NSString *)thePath 164 | { 165 | NSTask *mnt = [[NSTask alloc] init]; 166 | NSPipe *pip = [[NSPipe alloc] init];; 167 | NSFileHandle *handle = [pip fileHandleForReading]; 168 | NSData *outData; 169 | [mnt setCurrentDirectoryPath:thePath]; 170 | [mnt setLaunchPath:commandBinary]; 171 | [mnt setArguments:commandArguments]; 172 | [mnt setStandardError:pip]; 173 | [mnt setStandardOutput:pip]; 174 | [mnt launch]; 175 | 176 | NSString *temp; 177 | NSMutableArray *lineArray = [[NSMutableArray alloc] init]; 178 | while((outData = [handle readDataToEndOfFile]) && [outData length]) 179 | { 180 | temp = [[NSString alloc] initWithData:outData encoding:NSASCIIStringEncoding]; 181 | [lineArray addObjectsFromArray:[temp componentsSeparatedByString:@"\n"]]; 182 | } 183 | temp = nil; 184 | if ([lineArray count] ==0) 185 | { 186 | return [NSArray arrayWithObject:@""]; //idiot proofing 187 | } 188 | return lineArray; 189 | } 190 | 191 | + (IDEWorkspaceTabController*)tabController{ 192 | NSWindowController *currentWindowController = [[NSApp keyWindow] windowController]; 193 | 194 | if ([currentWindowController isKindOfClass:NSClassFromString(@"XTWindowController")]) 195 | { 196 | currentWindowController = [XTrello prevWindowController]; 197 | } 198 | 199 | if ([currentWindowController isKindOfClass:NSClassFromString(@"IDEWorkspaceWindowController")]) { 200 | IDEWorkspaceWindowController *workspaceController = (IDEWorkspaceWindowController *)currentWindowController; 201 | 202 | return workspaceController.activeWorkspaceTabController; 203 | } 204 | return nil; 205 | } 206 | 207 | + (id)currentEditor { 208 | NSWindowController *currentWindowController = [[NSApp mainWindow] windowController]; 209 | 210 | if ([currentWindowController isKindOfClass:NSClassFromString(@"XTWindowController")]) 211 | { 212 | currentWindowController = [XTrello prevWindowController]; 213 | } 214 | 215 | if ([currentWindowController isKindOfClass:NSClassFromString(@"IDEWorkspaceWindowController")]) { 216 | IDEWorkspaceWindowController *workspaceController = (IDEWorkspaceWindowController *)currentWindowController; 217 | IDEEditorArea *editorArea = [workspaceController editorArea]; 218 | IDEEditorContext *editorContext = [editorArea lastActiveEditorContext]; 219 | return [editorContext editor]; 220 | } 221 | return nil; 222 | } 223 | + (IDEWorkspaceDocument *)currentWorkspaceDocument { 224 | NSWindowController *currentWindowController = [[NSApp mainWindow] windowController]; 225 | NSLog(@"cwc: %@", currentWindowController); 226 | 227 | if ([currentWindowController isKindOfClass:NSClassFromString(@"XTWindowController")]) 228 | { 229 | currentWindowController = [XTrello prevWindowController]; 230 | } 231 | 232 | id document = [currentWindowController document]; 233 | if (currentWindowController && [document isKindOfClass:NSClassFromString(@"IDEWorkspaceDocument")]) { 234 | return (IDEWorkspaceDocument *)document; 235 | } 236 | return nil; 237 | } 238 | 239 | + (IDESourceCodeDocument *)currentSourceCodeDocument { 240 | 241 | IDESourceCodeEditor *editor=[self currentEditor]; 242 | 243 | if ([editor isKindOfClass:NSClassFromString(@"IDESourceCodeEditor")]) { 244 | return editor.sourceCodeDocument; 245 | } 246 | 247 | if ([editor isKindOfClass:NSClassFromString(@"IDESourceCodeComparisonEditor")]) { 248 | if ([[(IDESourceCodeComparisonEditor*)editor primaryDocument] isKindOfClass:NSClassFromString(@"IDESourceCodeDocument")]) { 249 | return (id)[(IDESourceCodeComparisonEditor *)editor primaryDocument]; 250 | } 251 | } 252 | 253 | return nil; 254 | } 255 | 256 | + (IDESourceControlWorkspaceMonitor *)sourceControlMonitor 257 | { 258 | return [XTModel currentWorkspaceDocument].workspace.sourceControlWorkspaceMonitor; 259 | 260 | } 261 | 262 | //TESTME: some tests! 263 | /* 264 | + (NSString*)scannedStrings { 265 | NSArray* prefsStrings = [[NSUserDefaults standardUserDefaults] objectForKey:kXToDoTagsKey]; 266 | NSMutableArray* escapedStrings = [NSMutableArray arrayWithCapacity:[prefsStrings count]]; 267 | 268 | for (NSString* origStr in prefsStrings) { 269 | NSMutableString* str = [NSMutableString string]; 270 | 271 | for (NSUInteger i=0; i<[origStr length]; i++) { 272 | unichar c = [origStr characterAtIndex:i]; 273 | 274 | if (!isalpha(c) && ! isnumber(c)) { 275 | [str appendFormat:@"\\%C", c]; 276 | } else { 277 | [str appendFormat:@"%C", c]; 278 | } 279 | } 280 | 281 | [str appendFormat:@"\\:"]; 282 | 283 | [escapedStrings addObject:str]; 284 | } 285 | 286 | return [escapedStrings componentsJoinedByString:@"|"]; 287 | } 288 | */ 289 | 290 | typedef void(^OnFindedItem)(NSString *fullPath, BOOL isDirectory, BOOL *skipThis, BOOL *stopAll); 291 | + (void) scanFolder:(NSString*)folder findedItemBlock:(OnFindedItem)findedItemBlock 292 | { 293 | BOOL stopAll = NO; 294 | 295 | NSFileManager* localFileManager = [[NSFileManager alloc] init]; 296 | NSDirectoryEnumerationOptions option = NSDirectoryEnumerationSkipsHiddenFiles | NSDirectoryEnumerationSkipsPackageDescendants; 297 | NSDirectoryEnumerator* directoryEnumerator = [localFileManager enumeratorAtURL:[NSURL fileURLWithPath:folder] 298 | includingPropertiesForKeys:nil 299 | options:option 300 | errorHandler:nil]; 301 | for (NSURL* theURL in directoryEnumerator) 302 | { 303 | if (stopAll) 304 | { 305 | break; 306 | } 307 | 308 | NSString *fileName = nil; 309 | [theURL getResourceValue:&fileName forKey:NSURLNameKey error:NULL]; 310 | 311 | NSNumber *isDirectory = nil; 312 | [theURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:NULL]; 313 | 314 | BOOL skinThis = NO; 315 | 316 | BOOL directory = [isDirectory boolValue]; 317 | 318 | findedItemBlock([theURL path], directory, &skinThis, &stopAll); 319 | 320 | if (skinThis) 321 | { 322 | [directoryEnumerator skipDescendents]; 323 | } 324 | } 325 | } 326 | 327 | 328 | + (NSArray *)removeSubDirs:(NSArray*)dirs 329 | { 330 | // TODO: 331 | return dirs; 332 | } 333 | 334 | + (NSSet *)lowercaseFileTypes:(NSSet *)fileTypes 335 | { 336 | NSMutableSet *set = [NSMutableSet setWithCapacity:[fileTypes count]]; 337 | for (NSString * fileType in fileTypes) 338 | { 339 | [set addObject:[fileType lowercaseString]]; 340 | } 341 | return set; 342 | } 343 | 344 | + (NSArray*)findFileNameWithProjectPath:(NSString *)projectPath 345 | includeDirs:(NSArray *)includeDirs 346 | excludeDirs:(NSArray *)excludeDirs 347 | fileTypes:(NSSet *)fileTypes 348 | { 349 | includeDirs = [XTModel explandRootPathMacros:includeDirs projectPath:projectPath]; 350 | includeDirs = [XTModel removeSubDirs:includeDirs]; 351 | excludeDirs = [XTModel explandRootPathMacros:excludeDirs projectPath:projectPath]; 352 | excludeDirs = [XTModel removeSubDirs:excludeDirs]; 353 | fileTypes = [XTModel lowercaseFileTypes:fileTypes]; 354 | NSMutableArray *allFilePaths = [NSMutableArray arrayWithCapacity:1000]; 355 | for (NSString *includeDir in includeDirs) 356 | { 357 | [XTModel scanFolder:includeDir findedItemBlock:^(NSString *fullPath, BOOL isDirectory, BOOL *skipThis, BOOL *stopAll) { 358 | if (isDirectory) 359 | { 360 | for (NSString *excludeDir in excludeDirs) 361 | { 362 | if ([fullPath hasPrefix:excludeDir]) 363 | { 364 | *skipThis = YES; 365 | return; 366 | } 367 | } 368 | } 369 | else 370 | { 371 | if ([fileTypes containsObject:[[fullPath pathExtension] lowercaseString]]) 372 | { 373 | [allFilePaths addObject:fullPath]; 374 | } 375 | } 376 | 377 | }]; 378 | } 379 | return allFilePaths; 380 | } 381 | 382 | 383 | 384 | 385 | + (NSString *) _settingDirectory 386 | { 387 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 388 | // TODO [path count] == 0 389 | NSString *settingDirectory = [(NSString *)[paths objectAtIndex:0] stringByAppendingPathComponent:@"GMDeploy"]; 390 | if ([[NSFileManager defaultManager] fileExistsAtPath:settingDirectory] == NO) 391 | { 392 | [[NSFileManager defaultManager] createDirectoryAtPath:settingDirectory 393 | withIntermediateDirectories:YES 394 | attributes:nil 395 | error:NULL]; 396 | } 397 | return settingDirectory; 398 | } 399 | 400 | + (NSString *) _tempFileDirectory 401 | { 402 | NSString *tempFileDirectory = [[XTModel _settingDirectory] stringByAppendingPathComponent:@"Temp"]; 403 | if ([[NSFileManager defaultManager] fileExistsAtPath:tempFileDirectory] == NO) 404 | { 405 | [[NSFileManager defaultManager] createDirectoryAtPath:tempFileDirectory 406 | withIntermediateDirectories:YES 407 | attributes:nil 408 | error:NULL]; 409 | } 410 | return tempFileDirectory; 411 | } 412 | 413 | + (void) cleanAllTempFiles 414 | { 415 | [XTModel scanFolder:[XTModel _tempFileDirectory] findedItemBlock:^(NSString *fullPath, BOOL isDirectory, BOOL *skipThis, BOOL *stopAll) { 416 | [[NSFileManager defaultManager] removeItemAtPath:fullPath error:nil]; 417 | }]; 418 | } 419 | 420 | + (NSString *)currentProjectName 421 | { 422 | NSString *filePath = [XTModel currentWorkspaceDocument].workspace.name; 423 | //NSString *projectDir= [filePath stringByDeletingLastPathComponent]; 424 | return filePath; 425 | } 426 | 427 | + (NSString *)currentProjectFile 428 | { 429 | NSString *filePath = [[XTModel currentWorkspaceDocument].workspace.representingFilePath.fileURL path]; 430 | //NSString *projectDir= [filePath stringByDeletingLastPathComponent]; 431 | return filePath; 432 | } 433 | 434 | + (NSString *)currentRootPath 435 | { 436 | NSString *filePath = [[XTModel currentWorkspaceDocument].workspace.representingFilePath.fileURL path]; 437 | return [filePath stringByDeletingLastPathComponent]; 438 | } 439 | 440 | + (NSString *) rootPathMacro 441 | { 442 | return [XTModel addPathSlash:@"$(SRCROOT)"]; 443 | } 444 | 445 | + (NSArray *) explandRootPathMacros:(NSArray *)paths projectPath:(NSString *)projectPath 446 | { 447 | if (projectPath == nil) 448 | { 449 | return paths; 450 | } 451 | 452 | NSMutableArray *explandPaths = [NSMutableArray arrayWithCapacity:[paths count]]; 453 | for (NSString *path in paths) { 454 | [explandPaths addObject:[XTModel explandRootPathMacro:path projectPath:projectPath]]; 455 | } 456 | return explandPaths; 457 | } 458 | 459 | + (NSString *) addPathSlash:(NSString *)path 460 | { 461 | if ([path length] > 0) 462 | { 463 | if ([path characterAtIndex:([path length] - 1)] != '/') 464 | { 465 | path = [NSString stringWithFormat:@"%@/", path]; 466 | } 467 | } 468 | return path; 469 | } 470 | 471 | + (NSString *) explandRootPathMacro:(NSString *)path projectPath:(NSString *)projectPath 472 | { 473 | projectPath = [XTModel addPathSlash:projectPath]; 474 | path = [path stringByReplacingOccurrencesOfString:[XTModel rootPathMacro] withString:projectPath]; 475 | 476 | return [XTModel addPathSlash:path]; 477 | } 478 | 479 | + (NSString *) settingFilePathByProjectName:(NSString *)projectName 480 | { 481 | NSString *settingDirectory = [XTModel _settingDirectory]; 482 | NSString *fileName = [projectName length] ? projectName : @"Test.xcodeproj"; 483 | return [settingDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.plist",fileName]]; 484 | } 485 | 486 | 487 | 488 | + (XTProjectSetting *) projectSettingByProjectName:(NSString *)projectName 489 | { 490 | static NSMutableDictionary *projectName2ProjectSetting = nil; 491 | if (projectName2ProjectSetting == nil) 492 | { 493 | projectName2ProjectSetting = [[NSMutableDictionary alloc] init]; 494 | } 495 | 496 | if (projectName != nil) 497 | { 498 | id object = [projectName2ProjectSetting objectForKey:projectName]; 499 | if ([object isKindOfClass:[XTProjectSetting class]]) 500 | { 501 | return object; 502 | } 503 | } 504 | 505 | NSString *fullPath = [XTModel settingFilePathByProjectName:projectName]; 506 | XTProjectSetting *projectSetting = nil; 507 | @try { 508 | projectSetting = [NSKeyedUnarchiver unarchiveObjectWithFile:fullPath]; 509 | } 510 | @catch (NSException *exception) { 511 | } 512 | if ([projectSetting isKindOfClass:[projectSetting class]] == NO){ 513 | projectSetting = nil; 514 | } 515 | 516 | if (projectSetting == nil) { 517 | projectSetting = [XTProjectSetting defaultProjectSetting]; 518 | } 519 | if ((projectSetting != nil) && (projectName != nil)) 520 | { 521 | [projectName2ProjectSetting setObject:projectSetting forKey:projectName]; 522 | } 523 | return projectSetting; 524 | } 525 | 526 | + (void) saveProjectSetting:(XTProjectSetting *)projectSetting ByProjectName:(NSString *)projectName 527 | { 528 | if (projectSetting == nil) 529 | { 530 | return; 531 | } 532 | @try { 533 | NSString *filePath = [XTModel settingFilePathByProjectName:projectName]; 534 | [NSKeyedArchiver archiveRootObject:projectSetting 535 | toFile:filePath]; 536 | filePath = nil; 537 | } 538 | @catch (NSException *exception) { 539 | NSLog(@"saveProjectSetting:exception:%@", exception); 540 | } 541 | NSLog(@"haha"); 542 | } 543 | 544 | @end 545 | -------------------------------------------------------------------------------- /XTrello/XTProjectSetting.h: -------------------------------------------------------------------------------- 1 | // 2 | // XTProjectSetting 3 | // XToDo 4 | // 5 | // Created by shuice on 2014-03-08. 6 | // Copyright (c) 2014. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface XTProjectSetting : NSObject 12 | @property NSArray *includeDirs; 13 | @property NSArray *excludeDirs; 14 | + (XTProjectSetting *) defaultProjectSetting; 15 | - (NSString *) firstIncludeDir; 16 | @end -------------------------------------------------------------------------------- /XTrello/XTProjectSetting.m: -------------------------------------------------------------------------------- 1 | // 2 | // XTProjectSetting 3 | // XToDo 4 | // 5 | // Created by shuice on 2014-03-08. 6 | // Copyright (c) 2014. All rights reserved. 7 | // 8 | 9 | #import "XTProjectSetting.h" 10 | #import "XTModel.h" 11 | 12 | @implementation XTProjectSetting 13 | 14 | - (void)encodeWithCoder:(NSCoder *)aCoder 15 | { 16 | [aCoder encodeObject:self.includeDirs ? self.includeDirs : @[] forKey:@"includeDirs"]; 17 | [aCoder encodeObject:self.excludeDirs ? self.excludeDirs : @[] forKey:@"excludeDirs"]; 18 | } 19 | 20 | - (id)initWithCoder:(NSCoder *)aDecoder 21 | { 22 | self = [super init]; 23 | if (self) 24 | { 25 | self.includeDirs = [aDecoder decodeObjectForKey:@"includeDirs"]; 26 | self.excludeDirs = [aDecoder decodeObjectForKey:@"excludeDirs"]; 27 | } 28 | return self; 29 | } 30 | 31 | + (XTProjectSetting *) defaultProjectSetting 32 | { 33 | XTProjectSetting *projectSetting = [[XTProjectSetting alloc] init]; 34 | projectSetting.includeDirs = @[[XTModel rootPathMacro]]; 35 | projectSetting.excludeDirs = @[[XTModel addPathSlash:[[XTModel rootPathMacro] stringByAppendingPathComponent:@"Pods"]]]; 36 | return projectSetting; 37 | } 38 | 39 | - (NSString *)firstIncludeDir 40 | { 41 | NSString *firstDir = [self.includeDirs count] ? [self.includeDirs objectAtIndex:0] : @""; 42 | if ([firstDir length] == 0) 43 | { 44 | firstDir = [XTModel rootPathMacro]; 45 | } 46 | return firstDir; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /XTrello/XTWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XTWindowController.h 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/14/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "XTTableView.h" 11 | #import 12 | #import "XTTrelloCardView.h" 13 | #import "XTrelloItem.h" 14 | 15 | @protocol XTWindowControllerDelegate 16 | 17 | - (void)removeItemForWindowTag:(NSInteger)windowTag; 18 | - (void)addItemForWindowTag:(NSInteger)windowTag; 19 | - (void)setPreviousWindowController:(NSWindowController *)windowController; 20 | - (NSArray *)trelloBoardArray; 21 | 22 | @end 23 | 24 | @interface XTWindowController : NSWindowController 25 | { 26 | NSArray *currentCardList; 27 | IBOutlet XTTableView *listTableView; 28 | // NSString *currentBoard; 29 | NSString *currentList; 30 | NSScrollView *theView; 31 | XTTrelloCardView *selectedView; 32 | NSInteger editingRow; 33 | 34 | XTTagViewController *tagViewController; 35 | IBOutlet WebView *webView; 36 | IBOutlet NSPopUpButton *boardPopup; 37 | 38 | IBOutlet NSArrayController *boardListController; 39 | IBOutlet NSArrayController *boardArrayController; 40 | IBOutlet NSWindow *prefWindow; 41 | IBOutlet NSTextField *apiKeyField; 42 | } 43 | @property (nonatomic, assign) IBOutlet NSWindow *windowTwo; 44 | @property (nonatomic, assign) id delegate; 45 | @property (nonatomic, strong) NSString *currentBoard; 46 | @property (nonatomic, assign) NSRange selectedLineRange; 47 | @property (nonatomic, retain) NSTextView *currentTextView; 48 | @property (nonatomic, assign) long selectedLineNumber; 49 | @property (nonatomic, retain) NSString *focalText; 50 | @property (readwrite, assign) BOOL boardsLoaded; 51 | 52 | - (IBAction)helpButtonPressed:(id)sender; 53 | - (int)boardCount; 54 | - (void)delayedResignFirstResponder; 55 | - (NSString *)currentProjectName; 56 | - (void)newCardFromMenu:(id)sender; 57 | - (void)setBoardArrayContent:(NSArray *)boardArray; 58 | - (void)populateCardsFromListNamed:(NSString *)listName inBoard:(NSString *)boardName; 59 | - (void)selectBoardNamed:(NSString *)boardName; 60 | - (IBAction)boardSelected:(id)sender; 61 | - (IBAction)listSelected:(id)sender; 62 | - (IBAction)addNewCard:(id)sender; 63 | - (IBAction)generateToken:(id)sender; 64 | - (IBAction)showPreferences:(id)sender; 65 | - (IBAction)refresh:(id)sender; 66 | - (void)dataReloaded; 67 | - (NSArray *)boardNames; 68 | - (NSArray *)boardArray; 69 | @end 70 | -------------------------------------------------------------------------------- /XTrello/XTrello-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.nito.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | BNDL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | DVTPlugInCompatibilityUUIDs 26 | 27 | C4A681B0-4A26-480E-93EC-1218098B9AA0 28 | 640F884E-CE55-4B40-87C0-8869546CAB7A 29 | 9F75337B-21B4-4ADC-B558-F9CADF7073A7 30 | 37B30044-3B14-46BA-ABAA-F01000C27B63 31 | A2E4D43F-41F4-4FB9-BB94-7177011C9AED 32 | 0420B86A-AA43-4792-9ED0-6FE0F2B16A13 33 | 7265231C-39B4-402C-89E1-16167C4CC990 34 | 9AFF134A-08DC-4096-8CEE-62A4BB123046 35 | F41BD31E-2683-44B8-AE7F-5F09E919790E 36 | E71C2CFE-BFD8-4044-8F06-00AE685A406C 37 | 0420B86A-AA43-4792-9ED0-6FE0F2B16A13 38 | ACA8656B-FEA8-4B6D-8E4A-93F4C95C362C 39 | E0A62D1F-3C18-4D74-BFE5-A4167D643966 40 | 8A66E736-A720-4B3C-92F1-33D9962C69DF 41 | DA4FDFD8-C509-4D8B-8B55-84A7B66AE701 42 | 43 | NSPrincipalClass 44 | XTrello 45 | XC4Compatible 46 | 47 | XC5Compatible 48 | 49 | XCGCReady 50 | 51 | XCPluginHasUI 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /XTrello/XTrello-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #ifdef __OBJC__ 8 | #import 9 | #import "NSString+trelloAdditions.h" 10 | #import "NSArray+trelloAdditions.h" 11 | #import "NSDictionary+trelloAdditions.h" 12 | #import "XTTrelloWrapper.h" 13 | #import "NSView+trelloAdditions.h" 14 | #import "NSString+trelloAdditions.h" 15 | #import "NSDictionary+trelloAdditions.h" 16 | #import "XTTrelloCardView.h" 17 | #import "XTMenuItem.h" 18 | #import "XTModel.h" 19 | #import "NSColor+Hex.h" 20 | 21 | static NSString* const kXTrelloAuthToken = @"trelloAuthToken"; 22 | static NSString* const kXTrelloAPIKey = @"trelloAPIKey"; 23 | static NSString* const kXTrelloRefreshRate = @"trelloRefreshRate"; 24 | static NSString* const kXTrelloPreferencesChanged = @"trelloPrefsChanged"; 25 | static NSString* const kXTrelloFloatingWindow = @"trelloFloatingWindow"; 26 | 27 | #define LOG_SELF NSLog(@"%@ %@", self, NSStringFromSelector(_cmd)) 28 | #define UD [NSUserDefaults standardUserDefaults] 29 | #endif 30 | -------------------------------------------------------------------------------- /XTrello/XTrello.h: -------------------------------------------------------------------------------- 1 | // 2 | // XTrello.h 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/14/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "XTTableView.h" 11 | #import "XTModel.h" 12 | #import "XTWindowController.h" 13 | 14 | 15 | 16 | @interface XTrello : NSObject 17 | { 18 | NSString *theToken; 19 | NSString *baseURL; 20 | NSString *apiKey; 21 | BOOL trelloReady; 22 | // NSDictionary *trelloData; 23 | NSMenuItem *xtrelloWindowMenuItem; 24 | NSMenuItem *xtrelloBrowserWindowMenuItem; 25 | NSTimer *refreshTimer; 26 | BOOL menuAdded; 27 | 28 | } 29 | 30 | @property (nonatomic, strong) NSDictionary *trelloData; 31 | @property (nonatomic, strong) NSWindowController *previousWindowController; 32 | 33 | + (NSWindowController *)prevWindowController; 34 | - (NSArray *)trelloBoardArray; 35 | @end -------------------------------------------------------------------------------- /XTrello/XTrelloItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // XTrelloItem.h 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/15/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface XTrelloItem : NSObject 12 | 13 | @property (nonatomic, copy) NSString* filePath; 14 | @property (nonatomic, assign) NSUInteger lineNumber; 15 | @property (nonatomic, copy) NSString* content; 16 | @property (nonatomic, copy) NSString* branch; 17 | 18 | - (id)initWithString:(NSString *)theString; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /XTrello/XTrelloItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // XTrelloItem.m 3 | // XTrello 4 | // 5 | // Created by Kevin Bradley on 7/15/14. 6 | // Copyright (c) 2014 Kevin Bradley. All rights reserved. 7 | // 8 | 9 | #import "XTrelloItem.h" 10 | 11 | @implementation XTrelloItem 12 | 13 | /* 14 | 15 | ~/Developer/XTrello/XTrello/Categories and Subclasses/NSString trelloAdditions.m 16 | branch: master 17 | line: 13 18 | - (NSString )tildePath 19 | { 20 | NSArray pathComponents = [self componentsSeparatedByString:@"/"]; 21 | NSArray *newPath = [pathComponents subarrayWithRange:NSMakeRange(3, pathComponents.count - 3)]; 22 | return [NSString stringWithFormat:@"~/%@", [newPath componentsJoinedByString:@"/"]]; 23 | } 24 | 25 | 26 | */ 27 | 28 | - (id)initWithString:(NSString *)theString 29 | { 30 | if (self = [super init]) 31 | { 32 | NSArray *lineArray = [theString componentsSeparatedByString:@"\n"]; 33 | // NSLog(@"lineArrayCount: %lu", (unsigned long)lineArray.count); 34 | if ([lineArray count] > 5) 35 | { 36 | self.filePath = [[lineArray objectAtIndex:0] stringByExpandingTildeInPath]; 37 | self.branch = [[[lineArray objectAtIndex:1] componentsSeparatedByString:@":"] lastObject]; 38 | self.lineNumber = [[[[lineArray objectAtIndex:2] componentsSeparatedByString:@":"] lastObject] floatValue]; 39 | self.content = [[lineArray subarrayWithRange:NSMakeRange(3, lineArray.count-3)] componentsJoinedByString:@"\n"]; 40 | NSLog(@"filePath: %@ lineNumber: %lu", self.filePath, (unsigned long)self.lineNumber); 41 | } 42 | 43 | } 44 | 45 | return self; 46 | } 47 | @end 48 | -------------------------------------------------------------------------------- /XTrello/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /add_labels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lechium/XTrello/ea7bd33ef044d900f98b35063005ae15e810dff4/add_labels.png -------------------------------------------------------------------------------- /browser_window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lechium/XTrello/ea7bd33ef044d900f98b35063005ae15e810dff4/browser_window.png -------------------------------------------------------------------------------- /create_source_card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lechium/XTrello/ea7bd33ef044d900f98b35063005ae15e810dff4/create_source_card.png --------------------------------------------------------------------------------