├── .gitignore ├── .travis.yml ├── Carthage Support └── Info.plist ├── Example ├── Example.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Example.xcscheme ├── Example.xcworkspace │ └── contents.xcworkspacedata ├── Example │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ └── LaunchScreen.xib │ ├── BasicViewController.h │ ├── BasicViewController.m │ ├── BasicViewController.xib │ ├── CustomViewController.h │ ├── CustomViewController.m │ ├── CustomViewController.xib │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Info.plist │ ├── SelectionViewController.h │ ├── SelectionViewController.m │ ├── SelectionViewController.xib │ ├── VerticalViewController.h │ ├── VerticalViewController.m │ ├── VerticalViewController.xib │ └── main.m ├── Podfile ├── Podfile.lock └── Pods │ ├── Headers │ ├── Private │ │ └── JTCalendar │ │ │ ├── JTCalendar.h │ │ │ ├── JTCalendarDay.h │ │ │ ├── JTCalendarDayView.h │ │ │ ├── JTCalendarDelegate.h │ │ │ ├── JTCalendarDelegateManager.h │ │ │ ├── JTCalendarManager.h │ │ │ ├── JTCalendarMenuView.h │ │ │ ├── JTCalendarPage.h │ │ │ ├── JTCalendarPageView.h │ │ │ ├── JTCalendarScrollManager.h │ │ │ ├── JTCalendarSettings.h │ │ │ ├── JTCalendarWeek.h │ │ │ ├── JTCalendarWeekDay.h │ │ │ ├── JTCalendarWeekDayView.h │ │ │ ├── JTCalendarWeekView.h │ │ │ ├── JTContent.h │ │ │ ├── JTDateHelper.h │ │ │ ├── JTHorizontalCalendarView.h │ │ │ ├── JTMenu.h │ │ │ └── JTVerticalCalendarView.h │ └── Public │ │ └── JTCalendar │ │ ├── JTCalendar.h │ │ ├── JTCalendarDay.h │ │ ├── JTCalendarDayView.h │ │ ├── JTCalendarDelegate.h │ │ ├── JTCalendarDelegateManager.h │ │ ├── JTCalendarManager.h │ │ ├── JTCalendarMenuView.h │ │ ├── JTCalendarPage.h │ │ ├── JTCalendarPageView.h │ │ ├── JTCalendarScrollManager.h │ │ ├── JTCalendarSettings.h │ │ ├── JTCalendarWeek.h │ │ ├── JTCalendarWeekDay.h │ │ ├── JTCalendarWeekDayView.h │ │ ├── JTCalendarWeekView.h │ │ ├── JTContent.h │ │ ├── JTDateHelper.h │ │ ├── JTHorizontalCalendarView.h │ │ ├── JTMenu.h │ │ └── JTVerticalCalendarView.h │ ├── Local Podspecs │ └── JTCalendar.podspec.json │ ├── Manifest.lock │ ├── Pods.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ └── JTCalendar.xcscheme │ └── Target Support Files │ ├── JTCalendar │ ├── JTCalendar-dummy.m │ ├── JTCalendar-prefix.pch │ └── JTCalendar.xcconfig │ └── Pods │ ├── Pods-acknowledgements.markdown │ ├── Pods-acknowledgements.plist │ ├── Pods-dummy.m │ ├── Pods-frameworks.sh │ ├── Pods-resources.sh │ ├── Pods.debug.xcconfig │ └── Pods.release.xcconfig ├── JTCalendar.podspec ├── JTCalendar.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── JTCalendar.xcscheme ├── JTCalendar ├── Info.plist ├── JTCalendar.h ├── JTCalendarDelegate.h ├── JTCalendarManager.h ├── JTCalendarManager.m ├── JTCalendarSettings.h ├── JTCalendarSettings.m ├── JTDateHelper.h ├── JTDateHelper.m ├── Managers │ ├── JTCalendarDelegateManager.h │ ├── JTCalendarDelegateManager.m │ ├── JTCalendarScrollManager.h │ └── JTCalendarScrollManager.m ├── Protocols │ ├── JTCalendarDay.h │ ├── JTCalendarPage.h │ ├── JTCalendarWeek.h │ ├── JTCalendarWeekDay.h │ ├── JTContent.h │ └── JTMenu.h └── Views │ ├── JTCalendarDayView.h │ ├── JTCalendarDayView.m │ ├── JTCalendarMenuView.h │ ├── JTCalendarMenuView.m │ ├── JTCalendarPageView.h │ ├── JTCalendarPageView.m │ ├── JTCalendarWeekDayView.h │ ├── JTCalendarWeekDayView.m │ ├── JTCalendarWeekView.h │ ├── JTCalendarWeekView.m │ ├── JTHorizontalCalendarView.h │ ├── JTHorizontalCalendarView.m │ ├── JTVerticalCalendarView.h │ └── JTVerticalCalendarView.m ├── LICENSE ├── README.md └── Screens ├── example.gif └── example.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac OS 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | xcode_workspace: Example/Example.xcworkspace 3 | xcode_scheme: Example 4 | xcode_sdk: iphonesimulator 5 | env: CODE_SIGN_IDENTITY=- CODE_SIGNING_REQUIRED=NO 6 | notifications: 7 | email: false -------------------------------------------------------------------------------- /Carthage Support/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | A478836B7E6915F6A886DADD /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A32EECC3DD04D628CA764863 /* libPods.a */; }; 11 | AB21D7A11B55570E006BC9D1 /* BasicViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AB21D79F1B55570E006BC9D1 /* BasicViewController.m */; }; 12 | AB21D7A21B55570E006BC9D1 /* BasicViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB21D7A01B55570E006BC9D1 /* BasicViewController.xib */; }; 13 | AB21D7A91B55572D006BC9D1 /* CustomViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AB21D7A71B55572D006BC9D1 /* CustomViewController.m */; }; 14 | AB21D7AA1B55572D006BC9D1 /* CustomViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB21D7A81B55572D006BC9D1 /* CustomViewController.xib */; }; 15 | AB21D7AE1B555738006BC9D1 /* SelectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AB21D7AC1B555738006BC9D1 /* SelectionViewController.m */; }; 16 | AB21D7AF1B555738006BC9D1 /* SelectionViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB21D7AD1B555738006BC9D1 /* SelectionViewController.xib */; }; 17 | AB21D7B41B55694B006BC9D1 /* VerticalViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AB21D7B21B55694B006BC9D1 /* VerticalViewController.m */; }; 18 | AB21D7B51B55694B006BC9D1 /* VerticalViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB21D7B31B55694B006BC9D1 /* VerticalViewController.xib */; }; 19 | AB6843E51A06FCE2000ADE68 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = AB6843E41A06FCE2000ADE68 /* main.m */; }; 20 | AB6843E81A06FCE2000ADE68 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = AB6843E71A06FCE2000ADE68 /* AppDelegate.m */; }; 21 | AB6843F01A06FCE2000ADE68 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AB6843EF1A06FCE2000ADE68 /* Images.xcassets */; }; 22 | AB6843F31A06FCE2000ADE68 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = AB6843F11A06FCE2000ADE68 /* LaunchScreen.xib */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | A32EECC3DD04D628CA764863 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | AB21D79E1B55570E006BC9D1 /* BasicViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BasicViewController.h; sourceTree = ""; }; 28 | AB21D79F1B55570E006BC9D1 /* BasicViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BasicViewController.m; sourceTree = ""; }; 29 | AB21D7A01B55570E006BC9D1 /* BasicViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BasicViewController.xib; sourceTree = ""; }; 30 | AB21D7A61B55572D006BC9D1 /* CustomViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomViewController.h; sourceTree = ""; }; 31 | AB21D7A71B55572D006BC9D1 /* CustomViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomViewController.m; sourceTree = ""; }; 32 | AB21D7A81B55572D006BC9D1 /* CustomViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CustomViewController.xib; sourceTree = ""; }; 33 | AB21D7AB1B555738006BC9D1 /* SelectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectionViewController.h; sourceTree = ""; }; 34 | AB21D7AC1B555738006BC9D1 /* SelectionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SelectionViewController.m; sourceTree = ""; }; 35 | AB21D7AD1B555738006BC9D1 /* SelectionViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SelectionViewController.xib; sourceTree = ""; }; 36 | AB21D7B11B55694B006BC9D1 /* VerticalViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VerticalViewController.h; sourceTree = ""; }; 37 | AB21D7B21B55694B006BC9D1 /* VerticalViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VerticalViewController.m; sourceTree = ""; }; 38 | AB21D7B31B55694B006BC9D1 /* VerticalViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = VerticalViewController.xib; sourceTree = ""; }; 39 | AB6843DF1A06FCE2000ADE68 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | AB6843E31A06FCE2000ADE68 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 41 | AB6843E41A06FCE2000ADE68 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 42 | AB6843E61A06FCE2000ADE68 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 43 | AB6843E71A06FCE2000ADE68 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 44 | AB6843EF1A06FCE2000ADE68 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 45 | AB6843F21A06FCE2000ADE68 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 46 | ACB1558A205302184CDC8B78 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 47 | EA29A33B12777736F86B89BA /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; 48 | /* End PBXFileReference section */ 49 | 50 | /* Begin PBXFrameworksBuildPhase section */ 51 | AB6843DC1A06FCE2000ADE68 /* Frameworks */ = { 52 | isa = PBXFrameworksBuildPhase; 53 | buildActionMask = 2147483647; 54 | files = ( 55 | A478836B7E6915F6A886DADD /* libPods.a in Frameworks */, 56 | ); 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | /* End PBXFrameworksBuildPhase section */ 60 | 61 | /* Begin PBXGroup section */ 62 | 614C882AD7264084D149FA72 /* Pods */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | EA29A33B12777736F86B89BA /* Pods.debug.xcconfig */, 66 | ACB1558A205302184CDC8B78 /* Pods.release.xcconfig */, 67 | ); 68 | name = Pods; 69 | sourceTree = ""; 70 | }; 71 | AB21D7B01B555839006BC9D1 /* Controllers */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | AB21D79E1B55570E006BC9D1 /* BasicViewController.h */, 75 | AB21D79F1B55570E006BC9D1 /* BasicViewController.m */, 76 | AB21D7A01B55570E006BC9D1 /* BasicViewController.xib */, 77 | AB21D7A61B55572D006BC9D1 /* CustomViewController.h */, 78 | AB21D7A71B55572D006BC9D1 /* CustomViewController.m */, 79 | AB21D7A81B55572D006BC9D1 /* CustomViewController.xib */, 80 | AB21D7AB1B555738006BC9D1 /* SelectionViewController.h */, 81 | AB21D7AC1B555738006BC9D1 /* SelectionViewController.m */, 82 | AB21D7AD1B555738006BC9D1 /* SelectionViewController.xib */, 83 | AB21D7B11B55694B006BC9D1 /* VerticalViewController.h */, 84 | AB21D7B21B55694B006BC9D1 /* VerticalViewController.m */, 85 | AB21D7B31B55694B006BC9D1 /* VerticalViewController.xib */, 86 | ); 87 | name = Controllers; 88 | sourceTree = ""; 89 | }; 90 | AB6843D61A06FCE2000ADE68 = { 91 | isa = PBXGroup; 92 | children = ( 93 | AB6843E11A06FCE2000ADE68 /* Example */, 94 | AB6843E01A06FCE2000ADE68 /* Products */, 95 | 614C882AD7264084D149FA72 /* Pods */, 96 | AF6935C573AD6FA5BBD10BEC /* Frameworks */, 97 | ); 98 | sourceTree = ""; 99 | }; 100 | AB6843E01A06FCE2000ADE68 /* Products */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | AB6843DF1A06FCE2000ADE68 /* Example.app */, 104 | ); 105 | name = Products; 106 | sourceTree = ""; 107 | }; 108 | AB6843E11A06FCE2000ADE68 /* Example */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | AB21D7B01B555839006BC9D1 /* Controllers */, 112 | AB6843E61A06FCE2000ADE68 /* AppDelegate.h */, 113 | AB6843E71A06FCE2000ADE68 /* AppDelegate.m */, 114 | AB6843EF1A06FCE2000ADE68 /* Images.xcassets */, 115 | AB6843F11A06FCE2000ADE68 /* LaunchScreen.xib */, 116 | AB6843E21A06FCE2000ADE68 /* Supporting Files */, 117 | ); 118 | path = Example; 119 | sourceTree = ""; 120 | }; 121 | AB6843E21A06FCE2000ADE68 /* Supporting Files */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | AB6843E31A06FCE2000ADE68 /* Info.plist */, 125 | AB6843E41A06FCE2000ADE68 /* main.m */, 126 | ); 127 | name = "Supporting Files"; 128 | sourceTree = ""; 129 | }; 130 | AF6935C573AD6FA5BBD10BEC /* Frameworks */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | A32EECC3DD04D628CA764863 /* libPods.a */, 134 | ); 135 | name = Frameworks; 136 | sourceTree = ""; 137 | }; 138 | /* End PBXGroup section */ 139 | 140 | /* Begin PBXNativeTarget section */ 141 | AB6843DE1A06FCE2000ADE68 /* Example */ = { 142 | isa = PBXNativeTarget; 143 | buildConfigurationList = AB6844021A06FCE3000ADE68 /* Build configuration list for PBXNativeTarget "Example" */; 144 | buildPhases = ( 145 | E0E39738925637B9A2BEAEA2 /* Check Pods Manifest.lock */, 146 | AB6843DB1A06FCE2000ADE68 /* Sources */, 147 | AB6843DC1A06FCE2000ADE68 /* Frameworks */, 148 | AB6843DD1A06FCE2000ADE68 /* Resources */, 149 | DAEE24CF4026663FE0755656 /* Copy Pods Resources */, 150 | AD2C6F32B39EFC52F28F2F53 /* Embed Pods Frameworks */, 151 | ); 152 | buildRules = ( 153 | ); 154 | dependencies = ( 155 | ); 156 | name = Example; 157 | productName = Example; 158 | productReference = AB6843DF1A06FCE2000ADE68 /* Example.app */; 159 | productType = "com.apple.product-type.application"; 160 | }; 161 | /* End PBXNativeTarget section */ 162 | 163 | /* Begin PBXProject section */ 164 | AB6843D71A06FCE2000ADE68 /* Project object */ = { 165 | isa = PBXProject; 166 | attributes = { 167 | LastUpgradeCheck = 0720; 168 | ORGANIZATIONNAME = "Jonathan Tribouharet"; 169 | TargetAttributes = { 170 | AB6843DE1A06FCE2000ADE68 = { 171 | CreatedOnToolsVersion = 6.1; 172 | }; 173 | }; 174 | }; 175 | buildConfigurationList = AB6843DA1A06FCE2000ADE68 /* Build configuration list for PBXProject "Example" */; 176 | compatibilityVersion = "Xcode 3.2"; 177 | developmentRegion = English; 178 | hasScannedForEncodings = 0; 179 | knownRegions = ( 180 | en, 181 | Base, 182 | ); 183 | mainGroup = AB6843D61A06FCE2000ADE68; 184 | productRefGroup = AB6843E01A06FCE2000ADE68 /* Products */; 185 | projectDirPath = ""; 186 | projectRoot = ""; 187 | targets = ( 188 | AB6843DE1A06FCE2000ADE68 /* Example */, 189 | ); 190 | }; 191 | /* End PBXProject section */ 192 | 193 | /* Begin PBXResourcesBuildPhase section */ 194 | AB6843DD1A06FCE2000ADE68 /* Resources */ = { 195 | isa = PBXResourcesBuildPhase; 196 | buildActionMask = 2147483647; 197 | files = ( 198 | AB21D7AA1B55572D006BC9D1 /* CustomViewController.xib in Resources */, 199 | AB21D7A21B55570E006BC9D1 /* BasicViewController.xib in Resources */, 200 | AB21D7B51B55694B006BC9D1 /* VerticalViewController.xib in Resources */, 201 | AB21D7AF1B555738006BC9D1 /* SelectionViewController.xib in Resources */, 202 | AB6843F31A06FCE2000ADE68 /* LaunchScreen.xib in Resources */, 203 | AB6843F01A06FCE2000ADE68 /* Images.xcassets in Resources */, 204 | ); 205 | runOnlyForDeploymentPostprocessing = 0; 206 | }; 207 | /* End PBXResourcesBuildPhase section */ 208 | 209 | /* Begin PBXShellScriptBuildPhase section */ 210 | AD2C6F32B39EFC52F28F2F53 /* Embed Pods Frameworks */ = { 211 | isa = PBXShellScriptBuildPhase; 212 | buildActionMask = 2147483647; 213 | files = ( 214 | ); 215 | inputPaths = ( 216 | ); 217 | name = "Embed Pods Frameworks"; 218 | outputPaths = ( 219 | ); 220 | runOnlyForDeploymentPostprocessing = 0; 221 | shellPath = /bin/sh; 222 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n"; 223 | showEnvVarsInLog = 0; 224 | }; 225 | DAEE24CF4026663FE0755656 /* Copy Pods Resources */ = { 226 | isa = PBXShellScriptBuildPhase; 227 | buildActionMask = 2147483647; 228 | files = ( 229 | ); 230 | inputPaths = ( 231 | ); 232 | name = "Copy Pods Resources"; 233 | outputPaths = ( 234 | ); 235 | runOnlyForDeploymentPostprocessing = 0; 236 | shellPath = /bin/sh; 237 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; 238 | showEnvVarsInLog = 0; 239 | }; 240 | E0E39738925637B9A2BEAEA2 /* Check Pods Manifest.lock */ = { 241 | isa = PBXShellScriptBuildPhase; 242 | buildActionMask = 2147483647; 243 | files = ( 244 | ); 245 | inputPaths = ( 246 | ); 247 | name = "Check Pods Manifest.lock"; 248 | outputPaths = ( 249 | ); 250 | runOnlyForDeploymentPostprocessing = 0; 251 | shellPath = /bin/sh; 252 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 253 | showEnvVarsInLog = 0; 254 | }; 255 | /* End PBXShellScriptBuildPhase section */ 256 | 257 | /* Begin PBXSourcesBuildPhase section */ 258 | AB6843DB1A06FCE2000ADE68 /* Sources */ = { 259 | isa = PBXSourcesBuildPhase; 260 | buildActionMask = 2147483647; 261 | files = ( 262 | AB21D7A91B55572D006BC9D1 /* CustomViewController.m in Sources */, 263 | AB21D7A11B55570E006BC9D1 /* BasicViewController.m in Sources */, 264 | AB21D7B41B55694B006BC9D1 /* VerticalViewController.m in Sources */, 265 | AB6843E81A06FCE2000ADE68 /* AppDelegate.m in Sources */, 266 | AB6843E51A06FCE2000ADE68 /* main.m in Sources */, 267 | AB21D7AE1B555738006BC9D1 /* SelectionViewController.m in Sources */, 268 | ); 269 | runOnlyForDeploymentPostprocessing = 0; 270 | }; 271 | /* End PBXSourcesBuildPhase section */ 272 | 273 | /* Begin PBXVariantGroup section */ 274 | AB6843F11A06FCE2000ADE68 /* LaunchScreen.xib */ = { 275 | isa = PBXVariantGroup; 276 | children = ( 277 | AB6843F21A06FCE2000ADE68 /* Base */, 278 | ); 279 | name = LaunchScreen.xib; 280 | sourceTree = ""; 281 | }; 282 | /* End PBXVariantGroup section */ 283 | 284 | /* Begin XCBuildConfiguration section */ 285 | AB6844001A06FCE3000ADE68 /* Debug */ = { 286 | isa = XCBuildConfiguration; 287 | buildSettings = { 288 | ALWAYS_SEARCH_USER_PATHS = NO; 289 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 290 | CLANG_CXX_LIBRARY = "libc++"; 291 | CLANG_ENABLE_MODULES = YES; 292 | CLANG_ENABLE_OBJC_ARC = YES; 293 | CLANG_WARN_BOOL_CONVERSION = YES; 294 | CLANG_WARN_CONSTANT_CONVERSION = YES; 295 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 296 | CLANG_WARN_EMPTY_BODY = YES; 297 | CLANG_WARN_ENUM_CONVERSION = YES; 298 | CLANG_WARN_INT_CONVERSION = YES; 299 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 300 | CLANG_WARN_UNREACHABLE_CODE = YES; 301 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 302 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 303 | COPY_PHASE_STRIP = NO; 304 | ENABLE_STRICT_OBJC_MSGSEND = YES; 305 | ENABLE_TESTABILITY = YES; 306 | GCC_C_LANGUAGE_STANDARD = gnu99; 307 | GCC_DYNAMIC_NO_PIC = NO; 308 | GCC_OPTIMIZATION_LEVEL = 0; 309 | GCC_PREPROCESSOR_DEFINITIONS = ( 310 | "DEBUG=1", 311 | "$(inherited)", 312 | ); 313 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 314 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 315 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 316 | GCC_WARN_UNDECLARED_SELECTOR = YES; 317 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 318 | GCC_WARN_UNUSED_FUNCTION = YES; 319 | GCC_WARN_UNUSED_VARIABLE = YES; 320 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 321 | MTL_ENABLE_DEBUG_INFO = YES; 322 | ONLY_ACTIVE_ARCH = YES; 323 | SDKROOT = iphoneos; 324 | }; 325 | name = Debug; 326 | }; 327 | AB6844011A06FCE3000ADE68 /* Release */ = { 328 | isa = XCBuildConfiguration; 329 | buildSettings = { 330 | ALWAYS_SEARCH_USER_PATHS = NO; 331 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 332 | CLANG_CXX_LIBRARY = "libc++"; 333 | CLANG_ENABLE_MODULES = YES; 334 | CLANG_ENABLE_OBJC_ARC = YES; 335 | CLANG_WARN_BOOL_CONVERSION = YES; 336 | CLANG_WARN_CONSTANT_CONVERSION = YES; 337 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 338 | CLANG_WARN_EMPTY_BODY = YES; 339 | CLANG_WARN_ENUM_CONVERSION = YES; 340 | CLANG_WARN_INT_CONVERSION = YES; 341 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 342 | CLANG_WARN_UNREACHABLE_CODE = YES; 343 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 344 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 345 | COPY_PHASE_STRIP = YES; 346 | ENABLE_NS_ASSERTIONS = NO; 347 | ENABLE_STRICT_OBJC_MSGSEND = YES; 348 | GCC_C_LANGUAGE_STANDARD = gnu99; 349 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 350 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 351 | GCC_WARN_UNDECLARED_SELECTOR = YES; 352 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 353 | GCC_WARN_UNUSED_FUNCTION = YES; 354 | GCC_WARN_UNUSED_VARIABLE = YES; 355 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 356 | MTL_ENABLE_DEBUG_INFO = NO; 357 | SDKROOT = iphoneos; 358 | VALIDATE_PRODUCT = YES; 359 | }; 360 | name = Release; 361 | }; 362 | AB6844031A06FCE3000ADE68 /* Debug */ = { 363 | isa = XCBuildConfiguration; 364 | baseConfigurationReference = EA29A33B12777736F86B89BA /* Pods.debug.xcconfig */; 365 | buildSettings = { 366 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 367 | INFOPLIST_FILE = Example/Info.plist; 368 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 369 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 370 | PRODUCT_BUNDLE_IDENTIFIER = "fr.eivo.$(PRODUCT_NAME:rfc1034identifier)"; 371 | PRODUCT_NAME = "$(TARGET_NAME)"; 372 | }; 373 | name = Debug; 374 | }; 375 | AB6844041A06FCE3000ADE68 /* Release */ = { 376 | isa = XCBuildConfiguration; 377 | baseConfigurationReference = ACB1558A205302184CDC8B78 /* Pods.release.xcconfig */; 378 | buildSettings = { 379 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 380 | INFOPLIST_FILE = Example/Info.plist; 381 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 382 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 383 | PRODUCT_BUNDLE_IDENTIFIER = "fr.eivo.$(PRODUCT_NAME:rfc1034identifier)"; 384 | PRODUCT_NAME = "$(TARGET_NAME)"; 385 | }; 386 | name = Release; 387 | }; 388 | /* End XCBuildConfiguration section */ 389 | 390 | /* Begin XCConfigurationList section */ 391 | AB6843DA1A06FCE2000ADE68 /* Build configuration list for PBXProject "Example" */ = { 392 | isa = XCConfigurationList; 393 | buildConfigurations = ( 394 | AB6844001A06FCE3000ADE68 /* Debug */, 395 | AB6844011A06FCE3000ADE68 /* Release */, 396 | ); 397 | defaultConfigurationIsVisible = 0; 398 | defaultConfigurationName = Release; 399 | }; 400 | AB6844021A06FCE3000ADE68 /* Build configuration list for PBXNativeTarget "Example" */ = { 401 | isa = XCConfigurationList; 402 | buildConfigurations = ( 403 | AB6844031A06FCE3000ADE68 /* Debug */, 404 | AB6844041A06FCE3000ADE68 /* Release */, 405 | ); 406 | defaultConfigurationIsVisible = 0; 407 | defaultConfigurationName = Release; 408 | }; 409 | /* End XCConfigurationList section */ 410 | }; 411 | rootObject = AB6843D71A06FCE2000ADE68 /* Project object */; 412 | } 413 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 46 | 47 | 53 | 54 | 55 | 56 | 57 | 58 | 68 | 70 | 76 | 77 | 78 | 79 | 80 | 81 | 87 | 89 | 95 | 96 | 97 | 98 | 100 | 101 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /Example/Example.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/Example/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Example 4 | // 5 | // Created by Jonathan Tribouharet. 6 | // 7 | 8 | #import 9 | 10 | @interface AppDelegate : UIResponder 11 | 12 | @property (strong, nonatomic) UIWindow *window; 13 | 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /Example/Example/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Example 4 | // 5 | // Created by Jonathan Tribouharet. 6 | // 7 | 8 | #import "AppDelegate.h" 9 | 10 | #import "BasicViewController.h" 11 | #import "CustomViewController.h" 12 | #import "SelectionViewController.h" 13 | #import "VerticalViewController.h" 14 | 15 | @interface AppDelegate () 16 | 17 | @end 18 | 19 | @implementation AppDelegate 20 | 21 | 22 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 23 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 24 | [self.window makeKeyAndVisible]; 25 | 26 | UITabBarController *controller = [UITabBarController new]; 27 | self.window.rootViewController = controller; 28 | 29 | controller.viewControllers = @[ 30 | [BasicViewController new], 31 | [CustomViewController new], 32 | [SelectionViewController new], 33 | [VerticalViewController new] 34 | ]; 35 | 36 | return YES; 37 | } 38 | 39 | - (void)applicationWillResignActive:(UIApplication *)application { 40 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 41 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 42 | } 43 | 44 | - (void)applicationDidEnterBackground:(UIApplication *)application { 45 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 46 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 47 | } 48 | 49 | - (void)applicationWillEnterForeground:(UIApplication *)application { 50 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 51 | } 52 | 53 | - (void)applicationDidBecomeActive:(UIApplication *)application { 54 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 55 | } 56 | 57 | - (void)applicationWillTerminate:(UIApplication *)application { 58 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 59 | } 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /Example/Example/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Example/Example/BasicViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // BasicViewController.h 3 | // Example 4 | // 5 | // Created by Jonathan Tribouharet. 6 | // 7 | 8 | #import 9 | 10 | #import 11 | 12 | @interface BasicViewController : UIViewController 13 | 14 | @property (weak, nonatomic) IBOutlet JTCalendarMenuView *calendarMenuView; 15 | @property (weak, nonatomic) IBOutlet JTHorizontalCalendarView *calendarContentView; 16 | 17 | @property (strong, nonatomic) JTCalendarManager *calendarManager; 18 | 19 | @property (weak, nonatomic) IBOutlet NSLayoutConstraint *calendarContentViewHeight; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Example/Example/BasicViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // BasicViewController.m 3 | // Example 4 | // 5 | // Created by Jonathan Tribouharet. 6 | // 7 | 8 | #import "BasicViewController.h" 9 | 10 | 11 | @interface BasicViewController (){ 12 | NSMutableDictionary *_eventsByDate; 13 | 14 | NSDate *_todayDate; 15 | NSDate *_minDate; 16 | NSDate *_maxDate; 17 | 18 | NSDate *_dateSelected; 19 | } 20 | 21 | @end 22 | 23 | @implementation BasicViewController 24 | 25 | - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 26 | { 27 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 28 | if(!self){ 29 | return nil; 30 | } 31 | 32 | self.title = @"Basic"; 33 | 34 | return self; 35 | } 36 | 37 | - (void)viewDidLoad 38 | { 39 | [super viewDidLoad]; 40 | 41 | _calendarManager = [JTCalendarManager new]; 42 | _calendarManager.delegate = self; 43 | 44 | // Generate random events sort by date using a dateformatter for the demonstration 45 | [self createRandomEvents]; 46 | 47 | // Create a min and max date for limit the calendar, optional 48 | [self createMinAndMaxDate]; 49 | 50 | [_calendarManager setMenuView:_calendarMenuView]; 51 | [_calendarManager setContentView:_calendarContentView]; 52 | [_calendarManager setDate:_todayDate]; 53 | } 54 | 55 | #pragma mark - Buttons callback 56 | 57 | - (IBAction)didGoTodayTouch 58 | { 59 | [_calendarManager setDate:_todayDate]; 60 | } 61 | 62 | - (IBAction)didChangeModeTouch 63 | { 64 | _calendarManager.settings.weekModeEnabled = !_calendarManager.settings.weekModeEnabled; 65 | [_calendarManager reload]; 66 | 67 | CGFloat newHeight = 300; 68 | if(_calendarManager.settings.weekModeEnabled){ 69 | newHeight = 85.; 70 | } 71 | 72 | self.calendarContentViewHeight.constant = newHeight; 73 | [self.view layoutIfNeeded]; 74 | } 75 | 76 | #pragma mark - CalendarManager delegate 77 | 78 | // Exemple of implementation of prepareDayView method 79 | // Used to customize the appearance of dayView 80 | - (void)calendar:(JTCalendarManager *)calendar prepareDayView:(JTCalendarDayView *)dayView 81 | { 82 | // Today 83 | if([_calendarManager.dateHelper date:[NSDate date] isTheSameDayThan:dayView.date]){ 84 | dayView.circleView.hidden = NO; 85 | dayView.circleView.backgroundColor = [UIColor blueColor]; 86 | dayView.dotView.backgroundColor = [UIColor whiteColor]; 87 | dayView.textLabel.textColor = [UIColor whiteColor]; 88 | } 89 | // Selected date 90 | else if(_dateSelected && [_calendarManager.dateHelper date:_dateSelected isTheSameDayThan:dayView.date]){ 91 | dayView.circleView.hidden = NO; 92 | dayView.circleView.backgroundColor = [UIColor redColor]; 93 | dayView.dotView.backgroundColor = [UIColor whiteColor]; 94 | dayView.textLabel.textColor = [UIColor whiteColor]; 95 | } 96 | // Other month 97 | else if(![_calendarManager.dateHelper date:_calendarContentView.date isTheSameMonthThan:dayView.date]){ 98 | dayView.circleView.hidden = YES; 99 | dayView.dotView.backgroundColor = [UIColor redColor]; 100 | dayView.textLabel.textColor = [UIColor lightGrayColor]; 101 | } 102 | // Another day of the current month 103 | else{ 104 | dayView.circleView.hidden = YES; 105 | dayView.dotView.backgroundColor = [UIColor redColor]; 106 | dayView.textLabel.textColor = [UIColor blackColor]; 107 | } 108 | 109 | if([self haveEventForDay:dayView.date]){ 110 | dayView.dotView.hidden = NO; 111 | } 112 | else{ 113 | dayView.dotView.hidden = YES; 114 | } 115 | } 116 | 117 | - (void)calendar:(JTCalendarManager *)calendar didTouchDayView:(JTCalendarDayView *)dayView 118 | { 119 | _dateSelected = dayView.date; 120 | 121 | // Animation for the circleView 122 | dayView.circleView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.1, 0.1); 123 | [UIView transitionWithView:dayView 124 | duration:.3 125 | options:0 126 | animations:^{ 127 | dayView.circleView.transform = CGAffineTransformIdentity; 128 | [_calendarManager reload]; 129 | } completion:nil]; 130 | 131 | 132 | // Don't change page in week mode because block the selection of days in first and last weeks of the month 133 | if(_calendarManager.settings.weekModeEnabled){ 134 | return; 135 | } 136 | 137 | // Load the previous or next page if touch a day from another month 138 | 139 | if(![_calendarManager.dateHelper date:_calendarContentView.date isTheSameMonthThan:dayView.date]){ 140 | if([_calendarContentView.date compare:dayView.date] == NSOrderedAscending){ 141 | [_calendarContentView loadNextPageWithAnimation]; 142 | } 143 | else{ 144 | [_calendarContentView loadPreviousPageWithAnimation]; 145 | } 146 | } 147 | } 148 | 149 | #pragma mark - CalendarManager delegate - Page mangement 150 | 151 | // Used to limit the date for the calendar, optional 152 | - (BOOL)calendar:(JTCalendarManager *)calendar canDisplayPageWithDate:(NSDate *)date 153 | { 154 | return [_calendarManager.dateHelper date:date isEqualOrAfter:_minDate andEqualOrBefore:_maxDate]; 155 | } 156 | 157 | - (void)calendarDidLoadNextPage:(JTCalendarManager *)calendar 158 | { 159 | // NSLog(@"Next page loaded"); 160 | } 161 | 162 | - (void)calendarDidLoadPreviousPage:(JTCalendarManager *)calendar 163 | { 164 | // NSLog(@"Previous page loaded"); 165 | } 166 | 167 | #pragma mark - Fake data 168 | 169 | - (void)createMinAndMaxDate 170 | { 171 | _todayDate = [NSDate date]; 172 | 173 | // Min date will be 2 month before today 174 | _minDate = [_calendarManager.dateHelper addToDate:_todayDate months:-2]; 175 | 176 | // Max date will be 2 month after today 177 | _maxDate = [_calendarManager.dateHelper addToDate:_todayDate months:2]; 178 | } 179 | 180 | // Used only to have a key for _eventsByDate 181 | - (NSDateFormatter *)dateFormatter 182 | { 183 | static NSDateFormatter *dateFormatter; 184 | if(!dateFormatter){ 185 | dateFormatter = [NSDateFormatter new]; 186 | dateFormatter.dateFormat = @"dd-MM-yyyy"; 187 | } 188 | 189 | return dateFormatter; 190 | } 191 | 192 | - (BOOL)haveEventForDay:(NSDate *)date 193 | { 194 | NSString *key = [[self dateFormatter] stringFromDate:date]; 195 | 196 | if(_eventsByDate[key] && [_eventsByDate[key] count] > 0){ 197 | return YES; 198 | } 199 | 200 | return NO; 201 | 202 | } 203 | 204 | - (void)createRandomEvents 205 | { 206 | _eventsByDate = [NSMutableDictionary new]; 207 | 208 | for(int i = 0; i < 30; ++i){ 209 | // Generate 30 random dates between now and 60 days later 210 | NSDate *randomDate = [NSDate dateWithTimeInterval:(rand() % (3600 * 24 * 60)) sinceDate:[NSDate date]]; 211 | 212 | // Use the date as key for eventsByDate 213 | NSString *key = [[self dateFormatter] stringFromDate:randomDate]; 214 | 215 | if(!_eventsByDate[key]){ 216 | _eventsByDate[key] = [NSMutableArray new]; 217 | } 218 | 219 | [_eventsByDate[key] addObject:randomDate]; 220 | } 221 | } 222 | 223 | @end 224 | -------------------------------------------------------------------------------- /Example/Example/BasicViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 48 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Example/Example/CustomViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CustomViewController.h 3 | // Example 4 | // 5 | // Created by Jonathan Tribouharet. 6 | // 7 | 8 | #import 9 | 10 | #import 11 | 12 | @interface CustomViewController : UIViewController 13 | 14 | @property (weak, nonatomic) IBOutlet JTCalendarMenuView *calendarMenuView; 15 | @property (weak, nonatomic) IBOutlet JTHorizontalCalendarView *calendarContentView; 16 | 17 | @property (strong, nonatomic) JTCalendarManager *calendarManager; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Example/Example/CustomViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CustomViewController.m 3 | // Example 4 | // 5 | // Created by Jonathan Tribouharet. 6 | // 7 | 8 | #import "CustomViewController.h" 9 | 10 | @interface CustomViewController (){ 11 | NSMutableDictionary *_eventsByDate; 12 | 13 | NSDate *_dateSelected; 14 | } 15 | 16 | @end 17 | 18 | @implementation CustomViewController 19 | 20 | - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 21 | { 22 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 23 | if(!self){ 24 | return nil; 25 | } 26 | 27 | self.title = @"Custom"; 28 | 29 | return self; 30 | } 31 | 32 | - (void)viewDidLoad 33 | { 34 | [super viewDidLoad]; 35 | 36 | _calendarManager = [[JTCalendarManager alloc] initWithLocale:[NSLocale localeWithLocaleIdentifier:@"fr_FR"] andTimeZone:[NSTimeZone localTimeZone]]; 37 | _calendarManager.delegate = self; 38 | 39 | // Generate random events sort by date using a dateformatter for the demonstration 40 | [self createRandomEvents]; 41 | 42 | _calendarMenuView.contentRatio = .75; 43 | _calendarManager.settings.weekDayFormat = JTCalendarWeekDayFormatSingle; 44 | 45 | [_calendarManager setMenuView:_calendarMenuView]; 46 | [_calendarManager setContentView:_calendarContentView]; 47 | [_calendarManager setDate:[NSDate date]]; 48 | } 49 | 50 | #pragma mark - CalendarManager delegate 51 | 52 | // Exemple of implementation of prepareDayView method 53 | // Used to customize the appearance of dayView 54 | - (void)calendar:(JTCalendarManager *)calendar prepareDayView:(JTCalendarDayView *)dayView 55 | { 56 | dayView.hidden = NO; 57 | 58 | // Other month 59 | if([dayView isFromAnotherMonth]){ 60 | dayView.hidden = YES; 61 | } 62 | // Today 63 | else if([_calendarManager.dateHelper date:[NSDate date] isTheSameDayThan:dayView.date]){ 64 | dayView.circleView.hidden = NO; 65 | dayView.circleView.backgroundColor = [UIColor blueColor]; 66 | dayView.dotView.backgroundColor = [UIColor whiteColor]; 67 | dayView.textLabel.textColor = [UIColor whiteColor]; 68 | } 69 | // Selected date 70 | else if(_dateSelected && [_calendarManager.dateHelper date:_dateSelected isTheSameDayThan:dayView.date]){ 71 | dayView.circleView.hidden = NO; 72 | dayView.circleView.backgroundColor = [UIColor redColor]; 73 | dayView.dotView.backgroundColor = [UIColor whiteColor]; 74 | dayView.textLabel.textColor = [UIColor whiteColor]; 75 | } 76 | // Another day of the current month 77 | else{ 78 | dayView.circleView.hidden = YES; 79 | dayView.dotView.backgroundColor = [UIColor redColor]; 80 | dayView.textLabel.textColor = [UIColor blackColor]; 81 | } 82 | 83 | if([self haveEventForDay:dayView.date]){ 84 | dayView.dotView.hidden = NO; 85 | } 86 | else{ 87 | dayView.dotView.hidden = YES; 88 | } 89 | } 90 | 91 | - (void)calendar:(JTCalendarManager *)calendar didTouchDayView:(JTCalendarDayView *)dayView 92 | { 93 | _dateSelected = dayView.date; 94 | 95 | // Animation for the circleView 96 | dayView.circleView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.1, 0.1); 97 | [UIView transitionWithView:dayView 98 | duration:.3 99 | options:0 100 | animations:^{ 101 | dayView.circleView.transform = CGAffineTransformIdentity; 102 | [_calendarManager reload]; 103 | } completion:nil]; 104 | 105 | 106 | // Don't change page in week mode because block the selection of days in first and last weeks of the month 107 | if(_calendarManager.settings.weekModeEnabled){ 108 | return; 109 | } 110 | 111 | // Load the previous or next page if touch a day from another month 112 | 113 | if(![_calendarManager.dateHelper date:_calendarContentView.date isTheSameMonthThan:dayView.date]){ 114 | if([_calendarContentView.date compare:dayView.date] == NSOrderedAscending){ 115 | [_calendarContentView loadNextPageWithAnimation]; 116 | } 117 | else{ 118 | [_calendarContentView loadPreviousPageWithAnimation]; 119 | } 120 | } 121 | } 122 | 123 | #pragma mark - Views customization 124 | 125 | - (UIView *)calendarBuildMenuItemView:(JTCalendarManager *)calendar 126 | { 127 | UILabel *label = [UILabel new]; 128 | 129 | label.textAlignment = NSTextAlignmentCenter; 130 | label.font = [UIFont fontWithName:@"Avenir-Medium" size:16]; 131 | 132 | return label; 133 | } 134 | 135 | - (void)calendar:(JTCalendarManager *)calendar prepareMenuItemView:(UILabel *)menuItemView date:(NSDate *)date 136 | { 137 | static NSDateFormatter *dateFormatter; 138 | if(!dateFormatter){ 139 | dateFormatter = [NSDateFormatter new]; 140 | dateFormatter.dateFormat = @"MMMM yyyy"; 141 | 142 | dateFormatter.locale = _calendarManager.dateHelper.calendar.locale; 143 | dateFormatter.timeZone = _calendarManager.dateHelper.calendar.timeZone; 144 | } 145 | 146 | menuItemView.text = [dateFormatter stringFromDate:date]; 147 | } 148 | 149 | - (UIView *)calendarBuildWeekDayView:(JTCalendarManager *)calendar 150 | { 151 | JTCalendarWeekDayView *view = [JTCalendarWeekDayView new]; 152 | 153 | for(UILabel *label in view.dayViews){ 154 | label.textColor = [UIColor blackColor]; 155 | label.font = [UIFont fontWithName:@"Avenir-Light" size:14]; 156 | } 157 | 158 | return view; 159 | } 160 | 161 | - (UIView *)calendarBuildDayView:(JTCalendarManager *)calendar 162 | { 163 | JTCalendarDayView *view = [JTCalendarDayView new]; 164 | 165 | view.textLabel.font = [UIFont fontWithName:@"Avenir-Light" size:13]; 166 | 167 | view.circleRatio = .8; 168 | view.dotRatio = 1. / .9; 169 | 170 | return view; 171 | } 172 | 173 | #pragma mark - Fake data 174 | 175 | // Used only to have a key for _eventsByDate 176 | - (NSDateFormatter *)dateFormatter 177 | { 178 | static NSDateFormatter *dateFormatter; 179 | if(!dateFormatter){ 180 | dateFormatter = [NSDateFormatter new]; 181 | dateFormatter.dateFormat = @"dd-MM-yyyy"; 182 | } 183 | 184 | return dateFormatter; 185 | } 186 | 187 | - (BOOL)haveEventForDay:(NSDate *)date 188 | { 189 | NSString *key = [[self dateFormatter] stringFromDate:date]; 190 | 191 | if(_eventsByDate[key] && [_eventsByDate[key] count] > 0){ 192 | return YES; 193 | } 194 | 195 | return NO; 196 | 197 | } 198 | 199 | - (void)createRandomEvents 200 | { 201 | _eventsByDate = [NSMutableDictionary new]; 202 | 203 | for(int i = 0; i < 30; ++i){ 204 | // Generate 30 random dates between now and 60 days later 205 | NSDate *randomDate = [NSDate dateWithTimeInterval:(rand() % (3600 * 24 * 60)) sinceDate:[NSDate date]]; 206 | 207 | // Use the date as key for eventsByDate 208 | NSString *key = [[self dateFormatter] stringFromDate:randomDate]; 209 | 210 | if(!_eventsByDate[key]){ 211 | _eventsByDate[key] = [NSMutableArray new]; 212 | } 213 | 214 | [_eventsByDate[key] addObject:randomDate]; 215 | } 216 | } 217 | 218 | @end 219 | -------------------------------------------------------------------------------- /Example/Example/CustomViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /Example/Example/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Example/Example/SelectionViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SelectionViewController.h 3 | // Example 4 | // 5 | // Created by Jonathan Tribouharet. 6 | // 7 | 8 | #import 9 | 10 | #import 11 | 12 | @interface SelectionViewController : UIViewController 13 | 14 | @property (weak, nonatomic) IBOutlet JTCalendarMenuView *calendarMenuView; 15 | @property (weak, nonatomic) IBOutlet JTHorizontalCalendarView *calendarContentView; 16 | 17 | @property (strong, nonatomic) JTCalendarManager *calendarManager; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Example/Example/SelectionViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SelectionViewController.m 3 | // Example 4 | // 5 | // Created by Jonathan Tribouharet. 6 | // 7 | 8 | #import "SelectionViewController.h" 9 | 10 | @interface SelectionViewController (){ 11 | NSMutableDictionary *_eventsByDate; 12 | 13 | NSMutableArray *_datesSelected; 14 | BOOL _selectionMode; 15 | } 16 | 17 | @end 18 | 19 | @implementation SelectionViewController 20 | 21 | - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 22 | { 23 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 24 | if(!self){ 25 | return nil; 26 | } 27 | 28 | self.title = @"Selection"; 29 | 30 | return self; 31 | } 32 | 33 | - (void)viewDidLoad 34 | { 35 | [super viewDidLoad]; 36 | 37 | _calendarManager = [JTCalendarManager new]; 38 | _calendarManager.delegate = self; 39 | 40 | // Generate random events sort by date using a dateformatter for the demonstration 41 | [self createRandomEvents]; 42 | 43 | [_calendarManager setMenuView:_calendarMenuView]; 44 | [_calendarManager setContentView:_calendarContentView]; 45 | [_calendarManager setDate:[NSDate date]]; 46 | 47 | _datesSelected = [NSMutableArray new]; 48 | _selectionMode = NO; 49 | } 50 | 51 | #pragma mark - Buttons callback 52 | 53 | - (IBAction)didSelectionModeTouch 54 | { 55 | _selectionMode = !_selectionMode; 56 | 57 | if(_selectionMode){ 58 | [_datesSelected removeAllObjects]; 59 | [_calendarManager reload]; 60 | } 61 | } 62 | 63 | #pragma mark - CalendarManager delegate 64 | 65 | // Exemple of implementation of prepareDayView method 66 | // Used to customize the appearance of dayView 67 | - (void)calendar:(JTCalendarManager *)calendar prepareDayView:(JTCalendarDayView *)dayView 68 | { 69 | // Today 70 | if([_calendarManager.dateHelper date:[NSDate date] isTheSameDayThan:dayView.date]){ 71 | dayView.circleView.hidden = NO; 72 | dayView.circleView.backgroundColor = [UIColor blueColor]; 73 | dayView.dotView.backgroundColor = [UIColor whiteColor]; 74 | dayView.textLabel.textColor = [UIColor whiteColor]; 75 | } 76 | // Selected date 77 | else if([self isInDatesSelected:dayView.date]){ 78 | dayView.circleView.hidden = NO; 79 | dayView.circleView.backgroundColor = [UIColor redColor]; 80 | dayView.dotView.backgroundColor = [UIColor whiteColor]; 81 | dayView.textLabel.textColor = [UIColor whiteColor]; 82 | } 83 | // Other month 84 | else if(![_calendarManager.dateHelper date:_calendarContentView.date isTheSameMonthThan:dayView.date]){ 85 | dayView.circleView.hidden = YES; 86 | dayView.dotView.backgroundColor = [UIColor redColor]; 87 | dayView.textLabel.textColor = [UIColor lightGrayColor]; 88 | } 89 | // Another day of the current month 90 | else{ 91 | dayView.circleView.hidden = YES; 92 | dayView.dotView.backgroundColor = [UIColor redColor]; 93 | dayView.textLabel.textColor = [UIColor blackColor]; 94 | } 95 | 96 | if([self haveEventForDay:dayView.date]){ 97 | dayView.dotView.hidden = NO; 98 | } 99 | else{ 100 | dayView.dotView.hidden = YES; 101 | } 102 | } 103 | 104 | - (void)calendar:(JTCalendarManager *)calendar didTouchDayView:(JTCalendarDayView *)dayView 105 | { 106 | if(_selectionMode && _datesSelected.count == 1 && ![_calendarManager.dateHelper date:[_datesSelected firstObject] isTheSameDayThan:dayView.date]){ 107 | [_datesSelected addObject:dayView.date]; 108 | [self selectDates]; 109 | _selectionMode = NO; 110 | [_calendarManager reload]; 111 | return; 112 | } 113 | 114 | 115 | if([self isInDatesSelected:dayView.date]){ 116 | [_datesSelected removeObject:dayView.date]; 117 | 118 | [UIView transitionWithView:dayView 119 | duration:.3 120 | options:0 121 | animations:^{ 122 | [_calendarManager reload]; 123 | dayView.circleView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.1, 0.1); 124 | } completion:nil]; 125 | } 126 | else{ 127 | [_datesSelected addObject:dayView.date]; 128 | 129 | dayView.circleView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.1, 0.1); 130 | [UIView transitionWithView:dayView 131 | duration:.3 132 | options:0 133 | animations:^{ 134 | [_calendarManager reload]; 135 | dayView.circleView.transform = CGAffineTransformIdentity; 136 | } completion:nil]; 137 | } 138 | 139 | if(_selectionMode) { 140 | return; 141 | } 142 | 143 | // Don't change page in week mode because block the selection of days in first and last weeks of the month 144 | if(_calendarManager.settings.weekModeEnabled){ 145 | return; 146 | } 147 | 148 | // Load the previous or next page if touch a day from another month 149 | 150 | if(![_calendarManager.dateHelper date:_calendarContentView.date isTheSameMonthThan:dayView.date]){ 151 | if([_calendarContentView.date compare:dayView.date] == NSOrderedAscending){ 152 | [_calendarContentView loadNextPageWithAnimation]; 153 | } 154 | else{ 155 | [_calendarContentView loadPreviousPageWithAnimation]; 156 | } 157 | } 158 | } 159 | 160 | #pragma mark - Date selection 161 | 162 | - (BOOL)isInDatesSelected:(NSDate *)date 163 | { 164 | for(NSDate *dateSelected in _datesSelected){ 165 | if([_calendarManager.dateHelper date:dateSelected isTheSameDayThan:date]){ 166 | return YES; 167 | } 168 | } 169 | 170 | return NO; 171 | } 172 | 173 | - (void)selectDates 174 | { 175 | NSDate * startDate = [_datesSelected firstObject]; 176 | NSDate * endDate = [_datesSelected lastObject]; 177 | 178 | if([_calendarManager.dateHelper date:startDate isEqualOrAfter:endDate]){ 179 | NSDate *nextDate = endDate; 180 | while ([nextDate compare:startDate] == NSOrderedAscending) { 181 | [_datesSelected addObject:nextDate]; 182 | nextDate = [_calendarManager.dateHelper addToDate:nextDate days:1]; 183 | } 184 | } 185 | else { 186 | NSDate *nextDate = startDate; 187 | while ([nextDate compare:endDate] == NSOrderedAscending) { 188 | [_datesSelected addObject:nextDate]; 189 | nextDate = [_calendarManager.dateHelper addToDate:nextDate days:1]; 190 | } 191 | } 192 | } 193 | 194 | #pragma mark - Fake data 195 | 196 | // Used only to have a key for _eventsByDate 197 | - (NSDateFormatter *)dateFormatter 198 | { 199 | static NSDateFormatter *dateFormatter; 200 | if(!dateFormatter){ 201 | dateFormatter = [NSDateFormatter new]; 202 | dateFormatter.dateFormat = @"dd-MM-yyyy"; 203 | } 204 | 205 | return dateFormatter; 206 | } 207 | 208 | - (BOOL)haveEventForDay:(NSDate *)date 209 | { 210 | NSString *key = [[self dateFormatter] stringFromDate:date]; 211 | 212 | if(_eventsByDate[key] && [_eventsByDate[key] count] > 0){ 213 | return YES; 214 | } 215 | 216 | return NO; 217 | 218 | } 219 | 220 | - (void)createRandomEvents 221 | { 222 | _eventsByDate = [NSMutableDictionary new]; 223 | 224 | for(int i = 0; i < 30; ++i){ 225 | // Generate 30 random dates between now and 60 days later 226 | NSDate *randomDate = [NSDate dateWithTimeInterval:(rand() % (3600 * 24 * 60)) sinceDate:[NSDate date]]; 227 | 228 | // Use the date as key for eventsByDate 229 | NSString *key = [[self dateFormatter] stringFromDate:randomDate]; 230 | 231 | if(!_eventsByDate[key]){ 232 | _eventsByDate[key] = [NSMutableArray new]; 233 | } 234 | 235 | [_eventsByDate[key] addObject:randomDate]; 236 | } 237 | } 238 | 239 | @end 240 | -------------------------------------------------------------------------------- /Example/Example/SelectionViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Example/Example/VerticalViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // VerticalViewController.h 3 | // Example 4 | // 5 | // Created by Jonathan Tribouharet. 6 | // 7 | 8 | #import 9 | 10 | #import 11 | 12 | @interface VerticalViewController : UIViewController 13 | 14 | @property (weak, nonatomic) IBOutlet JTCalendarMenuView *calendarMenuView; 15 | @property (weak, nonatomic) IBOutlet JTCalendarWeekDayView *weekDayView; 16 | @property (weak, nonatomic) IBOutlet JTVerticalCalendarView *calendarContentView; 17 | 18 | @property (strong, nonatomic) JTCalendarManager *calendarManager; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Example/Example/VerticalViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // VerticalViewController.m 3 | // Example 4 | // 5 | // Created by Jonathan Tribouharet. 6 | // 7 | 8 | #import "VerticalViewController.h" 9 | 10 | @interface VerticalViewController (){ 11 | NSMutableDictionary *_eventsByDate; 12 | 13 | NSDate *_dateSelected; 14 | } 15 | 16 | @end 17 | 18 | @implementation VerticalViewController 19 | 20 | - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 21 | { 22 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 23 | if(!self){ 24 | return nil; 25 | } 26 | 27 | self.title = @"Vertical"; 28 | 29 | return self; 30 | } 31 | 32 | - (void)viewDidLoad 33 | { 34 | [super viewDidLoad]; 35 | 36 | _calendarManager = [JTCalendarManager new]; 37 | _calendarManager.delegate = self; 38 | 39 | _calendarManager.settings.pageViewHaveWeekDaysView = NO; 40 | _calendarManager.settings.pageViewNumberOfWeeks = 0; // Automatic 41 | 42 | _weekDayView.manager = _calendarManager; 43 | [_weekDayView reload]; 44 | 45 | // Generate random events sort by date using a dateformatter for the demonstration 46 | [self createRandomEvents]; 47 | 48 | [_calendarManager setMenuView:_calendarMenuView]; 49 | [_calendarManager setContentView:_calendarContentView]; 50 | [_calendarManager setDate:[NSDate date]]; 51 | 52 | _calendarMenuView.scrollView.scrollEnabled = NO; // Scroll not supported with JTVerticalCalendarView 53 | } 54 | 55 | #pragma mark - CalendarManager delegate 56 | 57 | // Exemple of implementation of prepareDayView method 58 | // Used to customize the appearance of dayView 59 | - (void)calendar:(JTCalendarManager *)calendar prepareDayView:(JTCalendarDayView *)dayView 60 | { 61 | dayView.hidden = NO; 62 | 63 | // Hide if from another month 64 | if([dayView isFromAnotherMonth]){ 65 | dayView.hidden = YES; 66 | } 67 | // Today 68 | else if([_calendarManager.dateHelper date:[NSDate date] isTheSameDayThan:dayView.date]){ 69 | dayView.circleView.hidden = NO; 70 | dayView.circleView.backgroundColor = [UIColor blueColor]; 71 | dayView.dotView.backgroundColor = [UIColor whiteColor]; 72 | dayView.textLabel.textColor = [UIColor whiteColor]; 73 | } 74 | // Selected date 75 | else if(_dateSelected && [_calendarManager.dateHelper date:_dateSelected isTheSameDayThan:dayView.date]){ 76 | dayView.circleView.hidden = NO; 77 | dayView.circleView.backgroundColor = [UIColor redColor]; 78 | dayView.dotView.backgroundColor = [UIColor whiteColor]; 79 | dayView.textLabel.textColor = [UIColor whiteColor]; 80 | } 81 | // Other month 82 | else if(![_calendarManager.dateHelper date:_calendarContentView.date isTheSameMonthThan:dayView.date]){ 83 | dayView.circleView.hidden = YES; 84 | dayView.dotView.backgroundColor = [UIColor redColor]; 85 | dayView.textLabel.textColor = [UIColor lightGrayColor]; 86 | } 87 | // Another day of the current month 88 | else{ 89 | dayView.circleView.hidden = YES; 90 | dayView.dotView.backgroundColor = [UIColor redColor]; 91 | dayView.textLabel.textColor = [UIColor blackColor]; 92 | } 93 | 94 | if([self haveEventForDay:dayView.date]){ 95 | dayView.dotView.hidden = NO; 96 | } 97 | else{ 98 | dayView.dotView.hidden = YES; 99 | } 100 | } 101 | 102 | - (void)calendar:(JTCalendarManager *)calendar didTouchDayView:(JTCalendarDayView *)dayView 103 | { 104 | _dateSelected = dayView.date; 105 | 106 | // Animation for the circleView 107 | dayView.circleView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.1, 0.1); 108 | [UIView transitionWithView:dayView 109 | duration:.3 110 | options:0 111 | animations:^{ 112 | dayView.circleView.transform = CGAffineTransformIdentity; 113 | [_calendarManager reload]; 114 | } completion:nil]; 115 | 116 | 117 | // Don't change page in week mode because block the selection of days in first and last weeks of the month 118 | if(_calendarManager.settings.weekModeEnabled){ 119 | return; 120 | } 121 | 122 | // Load the previous or next page if touch a day from another month 123 | 124 | if(![_calendarManager.dateHelper date:_calendarContentView.date isTheSameMonthThan:dayView.date]){ 125 | if([_calendarContentView.date compare:dayView.date] == NSOrderedAscending){ 126 | [_calendarContentView loadNextPageWithAnimation]; 127 | } 128 | else{ 129 | [_calendarContentView loadPreviousPageWithAnimation]; 130 | } 131 | } 132 | } 133 | 134 | #pragma mark - Fake data 135 | 136 | // Used only to have a key for _eventsByDate 137 | - (NSDateFormatter *)dateFormatter 138 | { 139 | static NSDateFormatter *dateFormatter; 140 | if(!dateFormatter){ 141 | dateFormatter = [NSDateFormatter new]; 142 | dateFormatter.dateFormat = @"dd-MM-yyyy"; 143 | } 144 | 145 | return dateFormatter; 146 | } 147 | 148 | - (BOOL)haveEventForDay:(NSDate *)date 149 | { 150 | NSString *key = [[self dateFormatter] stringFromDate:date]; 151 | 152 | if(_eventsByDate[key] && [_eventsByDate[key] count] > 0){ 153 | return YES; 154 | } 155 | 156 | return NO; 157 | 158 | } 159 | 160 | - (void)createRandomEvents 161 | { 162 | _eventsByDate = [NSMutableDictionary new]; 163 | 164 | for(int i = 0; i < 30; ++i){ 165 | // Generate 30 random dates between now and 60 days later 166 | NSDate *randomDate = [NSDate dateWithTimeInterval:(rand() % (3600 * 24 * 60)) sinceDate:[NSDate date]]; 167 | 168 | // Use the date as key for eventsByDate 169 | NSString *key = [[self dateFormatter] stringFromDate:randomDate]; 170 | 171 | if(!_eventsByDate[key]){ 172 | _eventsByDate[key] = [NSMutableArray new]; 173 | } 174 | 175 | [_eventsByDate[key] addObject:randomDate]; 176 | } 177 | } 178 | 179 | @end 180 | -------------------------------------------------------------------------------- /Example/Example/VerticalViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Example/Example/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Example 4 | // 5 | // Created by Jonathan Tribouharet. 6 | // 7 | 8 | #import 9 | #import "AppDelegate.h" 10 | 11 | int main(int argc, char * argv[]) { 12 | @autoreleasepool { 13 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | 3 | platform :ios, '7.0' 4 | 5 | pod 'JTCalendar', path: '..' 6 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - JTCalendar (2.1.9) 3 | 4 | DEPENDENCIES: 5 | - JTCalendar (from `..`) 6 | 7 | EXTERNAL SOURCES: 8 | JTCalendar: 9 | :path: .. 10 | 11 | SPEC CHECKSUMS: 12 | JTCalendar: beb2f4c1b639bf6880f680b4858227acf83a049c 13 | 14 | COCOAPODS: 0.39.0 15 | -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTCalendar.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/JTCalendar.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTCalendarDay.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Protocols/JTCalendarDay.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTCalendarDayView.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Views/JTCalendarDayView.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTCalendarDelegate.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/JTCalendarDelegate.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTCalendarDelegateManager.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Managers/JTCalendarDelegateManager.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTCalendarManager.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/JTCalendarManager.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTCalendarMenuView.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Views/JTCalendarMenuView.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTCalendarPage.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Protocols/JTCalendarPage.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTCalendarPageView.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Views/JTCalendarPageView.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTCalendarScrollManager.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Managers/JTCalendarScrollManager.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTCalendarSettings.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/JTCalendarSettings.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTCalendarWeek.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Protocols/JTCalendarWeek.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTCalendarWeekDay.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Protocols/JTCalendarWeekDay.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTCalendarWeekDayView.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Views/JTCalendarWeekDayView.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTCalendarWeekView.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Views/JTCalendarWeekView.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTContent.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Protocols/JTContent.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTDateHelper.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/JTDateHelper.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTHorizontalCalendarView.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Views/JTHorizontalCalendarView.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTMenu.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Protocols/JTMenu.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Private/JTCalendar/JTVerticalCalendarView.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Views/JTVerticalCalendarView.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTCalendar.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/JTCalendar.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTCalendarDay.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Protocols/JTCalendarDay.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTCalendarDayView.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Views/JTCalendarDayView.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTCalendarDelegate.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/JTCalendarDelegate.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTCalendarDelegateManager.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Managers/JTCalendarDelegateManager.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTCalendarManager.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/JTCalendarManager.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTCalendarMenuView.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Views/JTCalendarMenuView.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTCalendarPage.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Protocols/JTCalendarPage.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTCalendarPageView.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Views/JTCalendarPageView.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTCalendarScrollManager.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Managers/JTCalendarScrollManager.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTCalendarSettings.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/JTCalendarSettings.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTCalendarWeek.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Protocols/JTCalendarWeek.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTCalendarWeekDay.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Protocols/JTCalendarWeekDay.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTCalendarWeekDayView.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Views/JTCalendarWeekDayView.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTCalendarWeekView.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Views/JTCalendarWeekView.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTContent.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Protocols/JTContent.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTDateHelper.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/JTDateHelper.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTHorizontalCalendarView.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Views/JTHorizontalCalendarView.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTMenu.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Protocols/JTMenu.h -------------------------------------------------------------------------------- /Example/Pods/Headers/Public/JTCalendar/JTVerticalCalendarView.h: -------------------------------------------------------------------------------- 1 | ../../../../../JTCalendar/Views/JTVerticalCalendarView.h -------------------------------------------------------------------------------- /Example/Pods/Local Podspecs/JTCalendar.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "JTCalendar", 3 | "version": "2.1.9", 4 | "summary": "A customizable calendar view for iOS.", 5 | "homepage": "https://github.com/jonathantribouharet/JTCalendar", 6 | "license": { 7 | "type": "MIT" 8 | }, 9 | "authors": { 10 | "Jonathan Tribouharet": "jonathan.tribouharet@gmail.com" 11 | }, 12 | "platforms": { 13 | "ios": "7.0" 14 | }, 15 | "source": { 16 | "git": "https://github.com/jonathantribouharet/JTCalendar.git", 17 | "tag": "2.1.9" 18 | }, 19 | "source_files": "JTCalendar/**/*", 20 | "requires_arc": true, 21 | "screenshots": [ 22 | "https://raw.githubusercontent.com/jonathantribouharet/JTCalendar/master/Screens/example.gif" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /Example/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - JTCalendar (2.1.9) 3 | 4 | DEPENDENCIES: 5 | - JTCalendar (from `..`) 6 | 7 | EXTERNAL SOURCES: 8 | JTCalendar: 9 | :path: .. 10 | 11 | SPEC CHECKSUMS: 12 | JTCalendar: beb2f4c1b639bf6880f680b4858227acf83a049c 13 | 14 | COCOAPODS: 0.39.0 15 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcshareddata/xcschemes/JTCalendar.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 52 | 53 | 55 | 56 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/JTCalendar/JTCalendar-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_JTCalendar : NSObject 3 | @end 4 | @implementation PodsDummy_JTCalendar 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/JTCalendar/JTCalendar-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #endif 4 | 5 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/JTCalendar/JTCalendar.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/JTCalendar" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/JTCalendar" 3 | PODS_ROOT = ${SRCROOT} 4 | SKIP_INSTALL = YES -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## JTCalendar 5 | 6 | Copyright (c) 2015 Jonathan Tribouharet 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | Generated by CocoaPods - http://cocoapods.org 26 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods/Pods-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Copyright (c) 2015 Jonathan Tribouharet 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | Title 37 | JTCalendar 38 | Type 39 | PSGroupSpecifier 40 | 41 | 42 | FooterText 43 | Generated by CocoaPods - http://cocoapods.org 44 | Title 45 | 46 | Type 47 | PSGroupSpecifier 48 | 49 | 50 | StringsTable 51 | Acknowledgements 52 | Title 53 | Acknowledgements 54 | 55 | 56 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods/Pods-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods : NSObject 3 | @end 4 | @implementation PodsDummy_Pods 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods/Pods-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | install_framework() 10 | { 11 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 12 | local source="${BUILT_PRODUCTS_DIR}/$1" 13 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 14 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 15 | elif [ -r "$1" ]; then 16 | local source="$1" 17 | fi 18 | 19 | local destination="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 20 | 21 | if [ -L "${source}" ]; then 22 | echo "Symlinked..." 23 | source="$(readlink "${source}")" 24 | fi 25 | 26 | # use filter instead of exclude so missing patterns dont' throw errors 27 | echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 28 | rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 29 | 30 | local basename 31 | basename="$(basename -s .framework "$1")" 32 | binary="${destination}/${basename}.framework/${basename}" 33 | if ! [ -r "$binary" ]; then 34 | binary="${destination}/${basename}" 35 | fi 36 | 37 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 38 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 39 | strip_invalid_archs "$binary" 40 | fi 41 | 42 | # Resign the code if required by the build settings to avoid unstable apps 43 | code_sign_if_enabled "${destination}/$(basename "$1")" 44 | 45 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 46 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 47 | local swift_runtime_libs 48 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 49 | for lib in $swift_runtime_libs; do 50 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 51 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 52 | code_sign_if_enabled "${destination}/${lib}" 53 | done 54 | fi 55 | } 56 | 57 | # Signs a framework with the provided identity 58 | code_sign_if_enabled() { 59 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 60 | # Use the current code_sign_identitiy 61 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 62 | echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements \"$1\"" 63 | /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements "$1" 64 | fi 65 | } 66 | 67 | # Strip invalid architectures 68 | strip_invalid_archs() { 69 | binary="$1" 70 | # Get architectures for current file 71 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 72 | stripped="" 73 | for arch in $archs; do 74 | if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then 75 | # Strip non-valid architectures in-place 76 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 77 | stripped="$stripped $arch" 78 | fi 79 | done 80 | if [[ "$stripped" ]]; then 81 | echo "Stripped $binary of architectures:$stripped" 82 | fi 83 | } 84 | 85 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods/Pods-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | realpath() { 12 | DIRECTORY="$(cd "${1%/*}" && pwd)" 13 | FILENAME="${1##*/}" 14 | echo "$DIRECTORY/$FILENAME" 15 | } 16 | 17 | install_resource() 18 | { 19 | case $1 in 20 | *.storyboard) 21 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}" 22 | ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" 23 | ;; 24 | *.xib) 25 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}" 26 | ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" 27 | ;; 28 | *.framework) 29 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 30 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 31 | echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 32 | rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 33 | ;; 34 | *.xcdatamodel) 35 | echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\"" 36 | xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom" 37 | ;; 38 | *.xcdatamodeld) 39 | echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\"" 40 | xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd" 41 | ;; 42 | *.xcmappingmodel) 43 | echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\"" 44 | xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm" 45 | ;; 46 | *.xcassets) 47 | ABSOLUTE_XCASSET_FILE=$(realpath "${PODS_ROOT}/$1") 48 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 49 | ;; 50 | /*) 51 | echo "$1" 52 | echo "$1" >> "$RESOURCES_TO_COPY" 53 | ;; 54 | *) 55 | echo "${PODS_ROOT}/$1" 56 | echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY" 57 | ;; 58 | esac 59 | } 60 | 61 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 62 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 63 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 64 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 65 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 66 | fi 67 | rm -f "$RESOURCES_TO_COPY" 68 | 69 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 70 | then 71 | case "${TARGETED_DEVICE_FAMILY}" in 72 | 1,2) 73 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 74 | ;; 75 | 1) 76 | TARGET_DEVICE_ARGS="--target-device iphone" 77 | ;; 78 | 2) 79 | TARGET_DEVICE_ARGS="--target-device ipad" 80 | ;; 81 | *) 82 | TARGET_DEVICE_ARGS="--target-device mac" 83 | ;; 84 | esac 85 | 86 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 87 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 88 | while read line; do 89 | if [[ $line != "`realpath $PODS_ROOT`*" ]]; then 90 | XCASSET_FILES+=("$line") 91 | fi 92 | done <<<"$OTHER_XCASSETS" 93 | 94 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 95 | fi 96 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods/Pods.debug.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/JTCalendar" 3 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/JTCalendar" 4 | OTHER_LDFLAGS = $(inherited) -ObjC -l"JTCalendar" 5 | PODS_ROOT = ${SRCROOT}/Pods -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods/Pods.release.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/JTCalendar" 3 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/JTCalendar" 4 | OTHER_LDFLAGS = $(inherited) -ObjC -l"JTCalendar" 5 | PODS_ROOT = ${SRCROOT}/Pods -------------------------------------------------------------------------------- /JTCalendar.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "JTCalendar" 3 | s.version = "2.2.6" 4 | s.summary = "A customizable calendar view for iOS." 5 | s.homepage = "https://github.com/jonathantribouharet/JTCalendar" 6 | s.license = { :type => 'MIT' } 7 | s.author = { "Jonathan VUKOVICH TRIBOUHARET" => "jonathan.tribouharet@gmail.com" } 8 | s.platform = :ios, '7.0' 9 | s.source = { :git => "https://github.com/jonathantribouharet/JTCalendar.git", :tag => s.version.to_s } 10 | s.source_files = 'JTCalendar/**/*.{h,m}' 11 | s.requires_arc = true 12 | s.screenshots = ["https://raw.githubusercontent.com/jonathantribouharet/JTCalendar/master/Screens/example.gif"] 13 | end 14 | -------------------------------------------------------------------------------- /JTCalendar.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /JTCalendar.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /JTCalendar.xcodeproj/xcshareddata/xcschemes/JTCalendar.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 72 | 73 | 74 | 75 | 77 | 78 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /JTCalendar/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /JTCalendar/JTCalendar.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendar.h 3 | // JTCalendar 4 | // 5 | // Created by Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | //! Project version number for JTCalendar. 11 | FOUNDATION_EXPORT double JTCalendarVersionNumber; 12 | 13 | //! Project version string for JTCalendar. 14 | FOUNDATION_EXPORT const unsigned char JTCalendarVersionString[]; 15 | 16 | // In this header, you should import all the public headers of your framework using statements 17 | #import "JTCalendarManager.h" 18 | 19 | #import "JTHorizontalCalendarView.h" 20 | #import "JTVerticalCalendarView.h" 21 | 22 | #import "JTCalendarMenuView.h" 23 | 24 | #import "JTCalendarPageView.h" 25 | #import "JTCalendarWeekDayView.h" 26 | #import "JTCalendarWeekView.h" 27 | #import "JTCalendarDayView.h" 28 | 29 | 30 | -------------------------------------------------------------------------------- /JTCalendar/JTCalendarDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarDelegate.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | #import "JTCalendarPage.h" 11 | #import "JTCalendarWeek.h" 12 | #import "JTCalendarWeekDay.h" 13 | #import "JTCalendarDay.h" 14 | 15 | @class JTCalendarManager; 16 | 17 | @protocol JTCalendarDelegate 18 | 19 | @optional 20 | 21 | 22 | // Menu view 23 | 24 | 25 | /*! 26 | * Provide a UIView, used as page for the menuView. 27 | * Return an instance of `UILabel` by default. 28 | */ 29 | - (UIView *_Nullable)calendarBuildMenuItemView:(JTCalendarManager *_Nullable)calendar; 30 | 31 | /*! 32 | * Used to customize the menuItemView. 33 | * Set text attribute to the name of the month by default. 34 | */ 35 | - (void)calendar:(JTCalendarManager *_Nullable)calendar prepareMenuItemView:(UIView *_Nullable)menuItemView date:(NSDate *_Nullable)date; 36 | 37 | 38 | // Content view 39 | 40 | 41 | /*! 42 | * Indicate if the calendar can go to this date. 43 | * Return `YES` by default. 44 | */ 45 | - (BOOL)calendar:(JTCalendarManager *_Nullable)calendar canDisplayPageWithDate:(NSDate *_Nullable)date; 46 | 47 | /*! 48 | * Provide the date for the previous page. 49 | * Return 1 month before the current date by default. 50 | */ 51 | - (NSDate *_Nullable)calendar:(JTCalendarManager *_Nullable)calendar dateForPreviousPageWithCurrentDate:(NSDate *_Nullable)currentDate; 52 | 53 | /*! 54 | * Provide the date for the next page. 55 | * Return 1 month after the current date by default. 56 | */ 57 | - (NSDate *_Nullable)calendar:(JTCalendarManager *_Nullable)calendar dateForNextPageWithCurrentDate:(NSDate *_Nullable)currentDate; 58 | 59 | /*! 60 | * Indicate the previous page became the current page. 61 | */ 62 | - (void)calendarDidLoadPreviousPage:(JTCalendarManager *_Nullable)calendar; 63 | 64 | /*! 65 | * Indicate the next page became the current page. 66 | */ 67 | - (void)calendarDidLoadNextPage:(JTCalendarManager *_Nullable)calendar; 68 | 69 | /*! 70 | * Provide a view conforming to `JTCalendarPage` protocol, used as page for the contentView. 71 | * Return an instance of `JTCalendarPageView` by default. 72 | */ 73 | - (UIView *_Nullable)calendarBuildPageView:(JTCalendarManager *_Nullable)calendar; 74 | 75 | 76 | // Page view 77 | 78 | 79 | /*! 80 | * Provide a view conforming to `JTCalendarWeekDay` protocol. 81 | * Return an instance of `JTCalendarWeekDayView` by default. 82 | */ 83 | - (UIView *_Nullable)calendarBuildWeekDayView:(JTCalendarManager *_Nullable)calendar; 84 | 85 | /*! 86 | * Provide a view conforming to `JTCalendarWeek` protocol. 87 | * Return an instance of `JTCalendarWeekView` by default. 88 | */ 89 | - (UIView *_Nullable)calendarBuildWeekView:(JTCalendarManager *_Nullable)calendar; 90 | 91 | 92 | // Week view 93 | 94 | 95 | /*! 96 | * Provide a view conforming to `JTCalendarDay` protocol. 97 | * Return an instance of `JTCalendarDayView` by default. 98 | */ 99 | - (UIView *_Nullable)calendarBuildDayView:(JTCalendarManager *_Nullable)calendar; 100 | 101 | 102 | // Day view 103 | 104 | 105 | /*! 106 | * Used to customize the dayView. 107 | */ 108 | - (void)calendar:(JTCalendarManager *_Nullable)calendar prepareDayView:(UIView *_Nullable)dayView; 109 | 110 | /*! 111 | * Indicate the dayView just get touched. 112 | */ 113 | - (void)calendar:(JTCalendarManager *_Nullable)calendar didTouchDayView:(UIView *_Nullable)dayView; 114 | 115 | @end 116 | -------------------------------------------------------------------------------- /JTCalendar/JTCalendarManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarManager.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | #import "JTCalendarDelegate.h" 11 | 12 | #import "JTContent.h" 13 | #import "JTMenu.h" 14 | 15 | #import "JTDateHelper.h" 16 | #import "JTCalendarSettings.h" 17 | 18 | #import "JTCalendarDelegateManager.h" 19 | #import "JTCalendarScrollManager.h" 20 | 21 | @interface JTCalendarManager : NSObject 22 | 23 | @property (nonatomic, weak, nullable) id delegate; 24 | 25 | @property (nonatomic, weak) UIView * _Nullable menuView; 26 | @property (nonatomic, weak) UIScrollView * _Nullable contentView; 27 | 28 | @property (nonatomic, readonly) JTDateHelper * _Nullable dateHelper; 29 | @property (nonatomic, readonly) JTCalendarSettings * _Nullable settings; 30 | 31 | // Intern methods 32 | 33 | @property (nonatomic, readonly) JTCalendarDelegateManager * _Nullable delegateManager; 34 | @property (nonatomic, readonly) JTCalendarScrollManager * _Nullable scrollManager; 35 | 36 | - (instancetype _Nullable )initWithLocale:(NSLocale *_Nullable)locale andTimeZone:(NSTimeZone *_Nullable)timeZone; 37 | 38 | - (NSDate *_Nonnull)date; 39 | - (void)setDate:(NSDate *_Nullable)date; 40 | - (void)reload; 41 | 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /JTCalendar/JTCalendarManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarManager.m 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import "JTCalendarManager.h" 9 | 10 | #import "JTHorizontalCalendarView.h" 11 | 12 | @implementation JTCalendarManager 13 | 14 | - (instancetype)init 15 | { 16 | return [self initWithLocale:[NSLocale currentLocale] andTimeZone:[NSTimeZone localTimeZone]]; 17 | } 18 | 19 | - (instancetype)initWithLocale:(NSLocale *)locale andTimeZone:(NSTimeZone *)timeZone 20 | { 21 | self = [super init]; 22 | if(!self){ 23 | return nil; 24 | } 25 | [self commonInit:locale andTimeZone:timeZone]; 26 | 27 | return self; 28 | } 29 | 30 | - (void)commonInit:(NSLocale *)locale andTimeZone:(NSTimeZone *)timeZone 31 | { 32 | _dateHelper = [[JTDateHelper alloc] initWithLocale:locale andTimeZone:timeZone]; 33 | _settings = [JTCalendarSettings new]; 34 | 35 | _delegateManager = [JTCalendarDelegateManager new]; 36 | _delegateManager.manager = self; 37 | 38 | _scrollManager = [JTCalendarScrollManager new]; 39 | _scrollManager.manager = self; 40 | } 41 | 42 | - (void)setContentView:(UIScrollView *)contentView 43 | { 44 | [_contentView setManager:nil]; 45 | self->_contentView = contentView; 46 | [_contentView setManager:self]; 47 | 48 | // Can only synchronise JTHorizontalCalendarView 49 | if([_contentView isKindOfClass:[JTHorizontalCalendarView class]]){ 50 | _scrollManager.horizontalContentView = _contentView; 51 | } 52 | else{ 53 | _scrollManager.horizontalContentView = nil; 54 | } 55 | } 56 | 57 | - (void)setMenuView:(UIScrollView *)menuView 58 | { 59 | [_menuView setManager:nil]; 60 | self->_menuView = menuView; 61 | [_menuView setManager:self]; 62 | 63 | _scrollManager.menuView = _menuView; 64 | } 65 | 66 | - (NSDate *)date 67 | { 68 | return _contentView.date; 69 | } 70 | 71 | - (void)setDate:(NSDate *)date 72 | { 73 | [_contentView setDate:date]; 74 | } 75 | 76 | - (void)reload 77 | { 78 | [_contentView setDate:_contentView.date]; 79 | } 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /JTCalendar/JTCalendarSettings.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarSettings.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | typedef NS_ENUM(NSInteger, JTCalendarWeekDayFormat) { 11 | JTCalendarWeekDayFormatSingle, 12 | JTCalendarWeekDayFormatShort, 13 | JTCalendarWeekDayFormatFull 14 | }; 15 | 16 | @interface JTCalendarSettings : NSObject 17 | 18 | 19 | // Content view 20 | 21 | @property (nonatomic) BOOL pageViewHideWhenPossible; 22 | @property (nonatomic) BOOL weekModeEnabled; 23 | 24 | 25 | // Page view 26 | 27 | // Must be less or equalt to 6, 0 for automatic 28 | @property (nonatomic) NSUInteger pageViewNumberOfWeeks; 29 | @property (nonatomic) BOOL pageViewHaveWeekDaysView; 30 | @property (nonatomic) NSUInteger pageViewWeekModeNumberOfWeeks; 31 | @property (nonatomic) BOOL pageViewWeekDaysViewAutomaticHeight; 32 | 33 | // WeekDay view 34 | 35 | @property (nonatomic) JTCalendarWeekDayFormat weekDayFormat; 36 | 37 | 38 | // Day view 39 | 40 | @property (nonatomic) BOOL zeroPaddedDayFormat; 41 | 42 | 43 | // Use for override 44 | - (void)commonInit; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /JTCalendar/JTCalendarSettings.m: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarSettings.m 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import "JTCalendarSettings.h" 9 | 10 | @implementation JTCalendarSettings 11 | 12 | - (instancetype)init 13 | { 14 | self = [super init]; 15 | if(!self){ 16 | return nil; 17 | } 18 | 19 | [self commonInit]; 20 | 21 | return self; 22 | } 23 | 24 | - (void)commonInit 25 | { 26 | _pageViewHideWhenPossible = NO; 27 | _pageViewNumberOfWeeks = 6; 28 | _pageViewHaveWeekDaysView = YES; 29 | _pageViewWeekDaysViewAutomaticHeight = NO; 30 | _weekDayFormat = JTCalendarWeekDayFormatShort; 31 | _zeroPaddedDayFormat = YES; 32 | _weekModeEnabled = NO; 33 | _pageViewWeekModeNumberOfWeeks = 1; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /JTCalendar/JTDateHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTDateHelper.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | @interface JTDateHelper : NSObject 11 | 12 | - initWithLocale:(NSLocale *)locale andTimeZone:(NSTimeZone *)timeZone; 13 | 14 | - (NSCalendar *)calendar; 15 | - (NSDateFormatter *)createDateFormatter; 16 | 17 | - (NSDate *)addToDate:(NSDate *)date months:(NSInteger)months; 18 | - (NSDate *)addToDate:(NSDate *)date weeks:(NSInteger)weeks; 19 | - (NSDate *)addToDate:(NSDate *)date days:(NSInteger)days; 20 | 21 | // Must be less or equal to 6 22 | - (NSUInteger)numberOfWeeks:(NSDate *)date; 23 | 24 | - (NSDate *)firstDayOfMonth:(NSDate *)date; 25 | - (NSDate *)firstWeekDayOfMonth:(NSDate *)date; 26 | - (NSDate *)firstWeekDayOfWeek:(NSDate *)date; 27 | 28 | - (BOOL)date:(NSDate *)dateA isTheSameMonthThan:(NSDate *)dateB; 29 | - (BOOL)date:(NSDate *)dateA isTheSameWeekThan:(NSDate *)dateB; 30 | - (BOOL)date:(NSDate *)dateA isTheSameDayThan:(NSDate *)dateB; 31 | 32 | - (BOOL)date:(NSDate *)dateA isEqualOrBefore:(NSDate *)dateB; 33 | - (BOOL)date:(NSDate *)dateA isEqualOrAfter:(NSDate *)dateB; 34 | - (BOOL)date:(NSDate *)date isEqualOrAfter:(NSDate *)startDate andEqualOrBefore:(NSDate *)endDate; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /JTCalendar/JTDateHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // JTDateHelper.m 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import "JTDateHelper.h" 9 | 10 | @interface JTDateHelper (){ 11 | NSCalendar *_calendar; 12 | NSLocale *_locale; 13 | NSTimeZone *_timeZone; 14 | } 15 | 16 | @end 17 | 18 | @implementation JTDateHelper 19 | 20 | - (instancetype)initWithLocale:(NSLocale *)locale andTimeZone:(NSTimeZone *)timeZone 21 | { 22 | self = [super init]; 23 | if (self) { 24 | _locale = locale; 25 | _timeZone = timeZone; 26 | } 27 | return self; 28 | } 29 | 30 | - (NSCalendar *)calendar 31 | { 32 | if(!_calendar){ 33 | #ifdef __IPHONE_8_0 34 | _calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; 35 | #else 36 | _calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 37 | #endif 38 | _calendar.timeZone = _timeZone; 39 | _calendar.locale = _locale; 40 | } 41 | 42 | return _calendar; 43 | } 44 | 45 | - (NSDateFormatter *)createDateFormatter 46 | { 47 | NSDateFormatter *dateFormatter = [NSDateFormatter new]; 48 | 49 | dateFormatter.timeZone = self.calendar.timeZone; 50 | dateFormatter.locale = self.calendar.locale; 51 | 52 | return dateFormatter; 53 | } 54 | 55 | #pragma mark - Operations 56 | 57 | - (NSDate *)addToDate:(NSDate *)date months:(NSInteger)months 58 | { 59 | NSDateComponents *components = [NSDateComponents new]; 60 | components.month = months; 61 | return [self.calendar dateByAddingComponents:components toDate:date options:0]; 62 | } 63 | 64 | - (NSDate *)addToDate:(NSDate *)date weeks:(NSInteger)weeks 65 | { 66 | NSDateComponents *components = [NSDateComponents new]; 67 | components.day = 7 * weeks; 68 | return [self.calendar dateByAddingComponents:components toDate:date options:0]; 69 | } 70 | 71 | - (NSDate *)addToDate:(NSDate *)date days:(NSInteger)days 72 | { 73 | NSDateComponents *components = [NSDateComponents new]; 74 | components.day = days; 75 | return [self.calendar dateByAddingComponents:components toDate:date options:0]; 76 | } 77 | 78 | #pragma mark - Helpers 79 | 80 | - (NSUInteger)numberOfWeeks:(NSDate *)date 81 | { 82 | NSDate *firstDay = [self firstDayOfMonth:date]; 83 | NSDate *lastDay = [self lastDayOfMonth:date]; 84 | 85 | NSDateComponents *componentsA = [self.calendar components:NSCalendarUnitWeekOfMonth fromDate:firstDay]; 86 | NSDateComponents *componentsB = [self.calendar components:NSCalendarUnitWeekOfMonth fromDate:lastDay]; 87 | 88 | return (componentsB.weekOfMonth - componentsA.weekOfMonth + 1); 89 | } 90 | 91 | - (NSDate *)firstDayOfMonth:(NSDate *)date 92 | { 93 | NSDateComponents *componentsCurrentDate = [self.calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitWeekday|NSCalendarUnitWeekOfMonth fromDate:date]; 94 | 95 | NSDateComponents *componentsNewDate = [NSDateComponents new]; 96 | 97 | componentsNewDate.year = componentsCurrentDate.year; 98 | componentsNewDate.month = componentsCurrentDate.month; 99 | componentsNewDate.weekOfMonth = 1; 100 | componentsNewDate.day = 1; 101 | 102 | return [self.calendar dateFromComponents:componentsNewDate]; 103 | } 104 | 105 | - (NSDate *)lastDayOfMonth:(NSDate *)date 106 | { 107 | NSDateComponents *componentsCurrentDate = [self.calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitWeekday|NSCalendarUnitWeekOfMonth fromDate:date]; 108 | 109 | NSDateComponents *componentsNewDate = [NSDateComponents new]; 110 | 111 | componentsNewDate.year = componentsCurrentDate.year; 112 | componentsNewDate.month = componentsCurrentDate.month + 1; 113 | componentsNewDate.day = 0; 114 | 115 | return [self.calendar dateFromComponents:componentsNewDate]; 116 | } 117 | 118 | - (NSDate *)firstWeekDayOfMonth:(NSDate *)date 119 | { 120 | NSDate *firstDayOfMonth = [self firstDayOfMonth:date]; 121 | return [self firstWeekDayOfWeek:firstDayOfMonth]; 122 | } 123 | 124 | - (NSDate *)firstWeekDayOfWeek:(NSDate *)date 125 | { 126 | NSDateComponents *componentsCurrentDate = [self.calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitWeekday|NSCalendarUnitWeekOfMonth fromDate:date]; 127 | 128 | NSDateComponents *componentsNewDate = [NSDateComponents new]; 129 | 130 | componentsNewDate.year = componentsCurrentDate.year; 131 | componentsNewDate.month = componentsCurrentDate.month; 132 | componentsNewDate.weekOfMonth = componentsCurrentDate.weekOfMonth; 133 | componentsNewDate.weekday = self.calendar.firstWeekday; 134 | 135 | return [self.calendar dateFromComponents:componentsNewDate]; 136 | } 137 | 138 | #pragma mark - Comparaison 139 | 140 | - (BOOL)date:(NSDate *)dateA isTheSameMonthThan:(NSDate *)dateB 141 | { 142 | NSDateComponents *componentsA = [self.calendar components:NSCalendarUnitYear|NSCalendarUnitMonth fromDate:dateA]; 143 | NSDateComponents *componentsB = [self.calendar components:NSCalendarUnitYear|NSCalendarUnitMonth fromDate:dateB]; 144 | 145 | return componentsA.year == componentsB.year && componentsA.month == componentsB.month; 146 | } 147 | 148 | - (BOOL)date:(NSDate *)dateA isTheSameWeekThan:(NSDate *)dateB 149 | { 150 | NSDateComponents *componentsA = [self.calendar components:NSCalendarUnitYear|NSCalendarUnitWeekOfYear fromDate:dateA]; 151 | NSDateComponents *componentsB = [self.calendar components:NSCalendarUnitYear|NSCalendarUnitWeekOfYear fromDate:dateB]; 152 | 153 | return componentsA.year == componentsB.year && componentsA.weekOfYear == componentsB.weekOfYear; 154 | } 155 | 156 | - (BOOL)date:(NSDate *)dateA isTheSameDayThan:(NSDate *)dateB 157 | { 158 | NSDateComponents *componentsA = [self.calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:dateA]; 159 | NSDateComponents *componentsB = [self.calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:dateB]; 160 | 161 | return componentsA.year == componentsB.year && componentsA.month == componentsB.month && componentsA.day == componentsB.day; 162 | } 163 | 164 | - (BOOL)date:(NSDate *)dateA isEqualOrBefore:(NSDate *)dateB 165 | { 166 | if([dateA compare:dateB] == NSOrderedAscending || [self date:dateA isTheSameDayThan:dateB]){ 167 | return YES; 168 | } 169 | 170 | return NO; 171 | } 172 | 173 | - (BOOL)date:(NSDate *)dateA isEqualOrAfter:(NSDate *)dateB 174 | { 175 | if([dateA compare:dateB] == NSOrderedDescending || [self date:dateA isTheSameDayThan:dateB]){ 176 | return YES; 177 | } 178 | 179 | return NO; 180 | } 181 | 182 | - (BOOL)date:(NSDate *)date isEqualOrAfter:(NSDate *)startDate andEqualOrBefore:(NSDate *)endDate 183 | { 184 | if([self date:date isEqualOrAfter:startDate] && [self date:date isEqualOrBefore:endDate]){ 185 | return YES; 186 | } 187 | 188 | return NO; 189 | } 190 | 191 | @end 192 | 193 | -------------------------------------------------------------------------------- /JTCalendar/Managers/JTCalendarDelegateManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarDelegateManager.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | #import "JTCalendarDelegate.h" 11 | 12 | // Provide a default behavior when no delegate are provided 13 | 14 | @interface JTCalendarDelegateManager : NSObject 15 | 16 | @property (nonatomic, weak) JTCalendarManager *manager; 17 | 18 | // Menu view 19 | 20 | - (UIView *)buildMenuItemView; 21 | - (void)prepareMenuItemView:(UIView *)menuItemView date:(NSDate *)date; 22 | 23 | // Content view 24 | 25 | - (UIView *)buildPageView; 26 | 27 | - (BOOL)canDisplayPageWithDate:(NSDate *)currentDate; 28 | 29 | - (NSDate *)dateForPreviousPageWithCurrentDate:(NSDate *)currentDate; 30 | - (NSDate *)dateForNextPageWithCurrentDate:(NSDate *)currentDate; 31 | 32 | // Page view 33 | 34 | - (UIView *)buildWeekDayView; 35 | - (UIView *)buildWeekView; 36 | 37 | 38 | // Week view 39 | 40 | - (UIView *)buildDayView; 41 | 42 | 43 | // Day view 44 | 45 | - (void)prepareDayView:(UIView *)dayView; 46 | - (void)didTouchDayView:(UIView *)dayView; 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /JTCalendar/Managers/JTCalendarDelegateManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarDelegateManager.m 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import "JTCalendarDelegateManager.h" 9 | 10 | #import "JTCalendarManager.h" 11 | 12 | #import "JTCalendarPageView.h" 13 | #import "JTCalendarWeekDayView.h" 14 | #import "JTCalendarWeekView.h" 15 | #import "JTCalendarDayView.h" 16 | 17 | @implementation JTCalendarDelegateManager 18 | 19 | #pragma mark - Menu view 20 | 21 | - (UIView *)buildMenuItemView 22 | { 23 | if(_manager.delegate && [_manager.delegate respondsToSelector:@selector(calendarBuildMenuItemView:)]){ 24 | return [_manager.delegate calendarBuildMenuItemView:self.manager]; 25 | } 26 | 27 | UILabel *label = [UILabel new]; 28 | label.textAlignment = NSTextAlignmentCenter; 29 | 30 | return label; 31 | } 32 | 33 | - (void)prepareMenuItemView:(UIView *)menuItemView date:(NSDate *)date 34 | { 35 | if(_manager.delegate && [_manager.delegate respondsToSelector:@selector(calendar:prepareMenuItemView:date:)]){ 36 | [_manager.delegate calendar:self.manager prepareMenuItemView:menuItemView date:date]; 37 | return; 38 | } 39 | 40 | NSString *text = nil; 41 | 42 | if(date){ 43 | NSCalendar *calendar = _manager.dateHelper.calendar; 44 | NSDateComponents *comps = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth fromDate:date]; 45 | NSInteger currentMonthIndex = comps.month; 46 | 47 | static NSDateFormatter *dateFormatter = nil; 48 | if(!dateFormatter){ 49 | dateFormatter = [_manager.dateHelper createDateFormatter]; 50 | } 51 | 52 | dateFormatter.timeZone = _manager.dateHelper.calendar.timeZone; 53 | dateFormatter.locale = _manager.dateHelper.calendar.locale; 54 | 55 | while(currentMonthIndex <= 0){ 56 | currentMonthIndex += 12; 57 | } 58 | 59 | text = [[dateFormatter standaloneMonthSymbols][currentMonthIndex - 1] capitalizedString]; 60 | } 61 | 62 | [(UILabel *)menuItemView setText:text]; 63 | } 64 | 65 | #pragma mark - Content view 66 | 67 | - (UIView *)buildPageView 68 | { 69 | if(_manager.delegate && [_manager.delegate respondsToSelector:@selector(calendarBuildPageView:)]){ 70 | return [_manager.delegate calendarBuildPageView:self.manager]; 71 | } 72 | 73 | return [JTCalendarPageView new]; 74 | } 75 | 76 | - (BOOL)canDisplayPageWithDate:(NSDate *)date 77 | { 78 | if(_manager.delegate && [_manager.delegate respondsToSelector:@selector(calendar:canDisplayPageWithDate:)]){ 79 | return [_manager.delegate calendar:self.manager canDisplayPageWithDate:date]; 80 | } 81 | 82 | return YES; 83 | } 84 | 85 | - (NSDate *)dateForPreviousPageWithCurrentDate:(NSDate *)currentDate 86 | { 87 | NSAssert(currentDate != nil, @"currentDate cannot be nil"); 88 | 89 | if(_manager.delegate && [_manager.delegate respondsToSelector:@selector(calendar:dateForPreviousPageWithCurrentDate:)]){ 90 | return [_manager.delegate calendar:self.manager dateForPreviousPageWithCurrentDate:currentDate]; 91 | } 92 | 93 | if(_manager.settings.weekModeEnabled){ 94 | return [_manager.dateHelper addToDate:currentDate weeks:-1]; 95 | } 96 | else{ 97 | return [_manager.dateHelper addToDate:currentDate months:-1]; 98 | } 99 | } 100 | 101 | - (NSDate *)dateForNextPageWithCurrentDate:(NSDate *)currentDate 102 | { 103 | NSAssert(currentDate != nil, @"currentDate cannot be nil"); 104 | 105 | if(_manager.delegate && [_manager.delegate respondsToSelector:@selector(calendar:dateForNextPageWithCurrentDate:)]){ 106 | return [_manager.delegate calendar:self.manager dateForNextPageWithCurrentDate:currentDate]; 107 | } 108 | 109 | if(_manager.settings.weekModeEnabled){ 110 | return [_manager.dateHelper addToDate:currentDate weeks:1]; 111 | } 112 | else{ 113 | return [_manager.dateHelper addToDate:currentDate months:1]; 114 | } 115 | } 116 | 117 | #pragma mark - Page view 118 | 119 | - (UIView *)buildWeekDayView 120 | { 121 | if(_manager.delegate && [_manager.delegate respondsToSelector:@selector(calendarBuildWeekDayView:)]){ 122 | return [_manager.delegate calendarBuildWeekDayView:self.manager]; 123 | } 124 | 125 | return [JTCalendarWeekDayView new]; 126 | } 127 | 128 | - (UIView *)buildWeekView 129 | { 130 | if(_manager.delegate && [_manager.delegate respondsToSelector:@selector(calendarBuildWeekView:)]){ 131 | return [_manager.delegate calendarBuildWeekView:self.manager]; 132 | } 133 | 134 | return [JTCalendarWeekView new]; 135 | } 136 | 137 | #pragma mark - Week view 138 | 139 | - (UIView *)buildDayView 140 | { 141 | if(_manager.delegate && [_manager.delegate respondsToSelector:@selector(calendarBuildDayView:)]){ 142 | return [_manager.delegate calendarBuildDayView:self.manager]; 143 | } 144 | 145 | return [JTCalendarDayView new]; 146 | } 147 | 148 | #pragma mark - Day view 149 | 150 | - (void)prepareDayView:(UIView *)dayView 151 | { 152 | if(_manager.delegate && [_manager.delegate respondsToSelector:@selector(calendar:prepareDayView:)]){ 153 | [_manager.delegate calendar:self.manager prepareDayView:dayView]; 154 | } 155 | } 156 | 157 | - (void)didTouchDayView:(UIView *)dayView 158 | { 159 | if(_manager.delegate && [_manager.delegate respondsToSelector:@selector(calendar:didTouchDayView:)]){ 160 | [_manager.delegate calendar:self.manager didTouchDayView:dayView]; 161 | } 162 | } 163 | 164 | @end 165 | -------------------------------------------------------------------------------- /JTCalendar/Managers/JTCalendarScrollManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarScrollManager.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | #import "JTCalendarDelegate.h" 11 | 12 | #import "JTMenu.h" 13 | #import "JTContent.h" 14 | 15 | // Synchronize JTHorizontalCalendarView and JTCalendarMenuView 16 | 17 | @interface JTCalendarScrollManager : NSObject 18 | 19 | @property (nonatomic, weak) JTCalendarManager *manager; 20 | 21 | @property (nonatomic, weak) UIView *menuView; 22 | @property (nonatomic, weak) UIScrollView *horizontalContentView; 23 | 24 | - (void)setMenuPreviousDate:(NSDate *)previousDate 25 | currentDate:(NSDate *)currentDate 26 | nextDate:(NSDate *)nextDate; 27 | 28 | - (void)updateMenuContentOffset:(CGFloat)percentage pageMode:(NSUInteger)pageMode; 29 | - (void)updateHorizontalContentOffset:(CGFloat)percentage; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /JTCalendar/Managers/JTCalendarScrollManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarScrollManager.m 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import "JTCalendarScrollManager.h" 9 | 10 | @implementation JTCalendarScrollManager 11 | 12 | - (void)setMenuPreviousDate:(NSDate *)previousDate 13 | currentDate:(NSDate *)currentDate 14 | nextDate:(NSDate *)nextDate 15 | { 16 | if(!_menuView){ 17 | return; 18 | } 19 | 20 | [_menuView setPreviousDate:previousDate currentDate:currentDate nextDate:nextDate]; 21 | } 22 | 23 | - (void)updateMenuContentOffset:(CGFloat)percentage pageMode:(NSUInteger)pageMode 24 | { 25 | if(!_menuView){ 26 | return; 27 | } 28 | 29 | [_menuView updatePageMode:pageMode]; 30 | _menuView.scrollView.contentOffset = CGPointMake(percentage * _menuView.scrollView.contentSize.width, 0); 31 | } 32 | 33 | - (void)updateHorizontalContentOffset:(CGFloat)percentage 34 | { 35 | if(!_horizontalContentView){ 36 | return; 37 | } 38 | 39 | _horizontalContentView.contentOffset = CGPointMake(percentage * _horizontalContentView.contentSize.width, 0); 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /JTCalendar/Protocols/JTCalendarDay.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarDay.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | @class JTCalendarManager; 11 | 12 | @protocol JTCalendarDay 13 | 14 | - (void)setManager:(JTCalendarManager *)manager; 15 | 16 | - (NSDate *)date; 17 | - (void)setDate:(NSDate *)date; 18 | 19 | - (BOOL)isFromAnotherMonth; 20 | - (void)setIsFromAnotherMonth:(BOOL)isFromAnotherMonth; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /JTCalendar/Protocols/JTCalendarPage.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarPage.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | @class JTCalendarManager; 11 | 12 | @protocol JTCalendarPage 13 | 14 | - (void)setManager:(JTCalendarManager *)manager; 15 | 16 | - (NSDate *)date; 17 | - (void)setDate:(NSDate *)date; 18 | 19 | - (void)reload; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /JTCalendar/Protocols/JTCalendarWeek.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarWeek.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | @class JTCalendarManager; 11 | 12 | @protocol JTCalendarWeek 13 | 14 | - (void)setManager:(JTCalendarManager *)manager; 15 | 16 | - (NSDate *)startDate; 17 | - (void)setStartDate:(NSDate *)startDate updateAnotherMonth:(BOOL)enable monthDate:(NSDate *)monthDate; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /JTCalendar/Protocols/JTCalendarWeekDay.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarWeekDay.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | @class JTCalendarManager; 11 | 12 | @protocol JTCalendarWeekDay 13 | 14 | - (void)setManager:(JTCalendarManager *)manager; 15 | 16 | - (void)reload; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /JTCalendar/Protocols/JTContent.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTContent.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | @class JTCalendarManager; 11 | 12 | @protocol JTContent 13 | 14 | - (void)setManager:(JTCalendarManager *)manager; 15 | 16 | - (NSDate *)date; 17 | - (void)setDate:(NSDate *)date; 18 | 19 | - (void)loadPreviousPage; 20 | - (void)loadNextPage; 21 | 22 | - (void)loadPreviousPageWithAnimation; 23 | - (void)loadNextPageWithAnimation; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /JTCalendar/Protocols/JTMenu.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTMenu.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | @class JTCalendarManager; 11 | 12 | @protocol JTMenu 13 | 14 | - (void)setManager:(JTCalendarManager *)manager; 15 | 16 | - (void)setPreviousDate:(NSDate *)previousDate 17 | currentDate:(NSDate *)currentDate 18 | nextDate:(NSDate *)nextDate; 19 | 20 | - (void)updatePageMode:(NSUInteger)pageMode; 21 | 22 | - (UIScrollView *)scrollView; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /JTCalendar/Views/JTCalendarDayView.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarDayView.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | #import "JTCalendarDay.h" 11 | 12 | @interface JTCalendarDayView : UIView 13 | 14 | @property (nonatomic, weak) JTCalendarManager *manager; 15 | 16 | @property (nonatomic) NSDate *date; 17 | 18 | @property (nonatomic, readonly) UIView *circleView; 19 | @property (nonatomic, readonly) UIView *dotView; 20 | @property (nonatomic, readonly) UILabel *textLabel; 21 | 22 | @property (nonatomic) CGFloat circleRatio; 23 | @property (nonatomic) CGFloat dotRatio; 24 | 25 | @property (nonatomic) BOOL isFromAnotherMonth; 26 | 27 | /*! 28 | * Must be call if override the class 29 | */ 30 | - (void)commonInit; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /JTCalendar/Views/JTCalendarDayView.m: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarDayView.m 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import "JTCalendarDayView.h" 9 | 10 | #import "JTCalendarManager.h" 11 | 12 | @implementation JTCalendarDayView 13 | 14 | - (instancetype)initWithFrame:(CGRect)frame 15 | { 16 | self = [super initWithFrame:frame]; 17 | if(!self){ 18 | return nil; 19 | } 20 | 21 | [self commonInit]; 22 | 23 | return self; 24 | } 25 | 26 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 27 | { 28 | self = [super initWithCoder:aDecoder]; 29 | if(!self){ 30 | return nil; 31 | } 32 | 33 | [self commonInit]; 34 | 35 | return self; 36 | } 37 | 38 | - (void)commonInit 39 | { 40 | self.clipsToBounds = YES; 41 | 42 | _circleRatio = .9; 43 | _dotRatio = 1. / 9.; 44 | 45 | { 46 | _circleView = [UIView new]; 47 | [self addSubview:_circleView]; 48 | 49 | _circleView.backgroundColor = [UIColor colorWithRed:0x33/256. green:0xB3/256. blue:0xEC/256. alpha:.5]; 50 | _circleView.hidden = YES; 51 | 52 | _circleView.layer.rasterizationScale = [UIScreen mainScreen].scale; 53 | _circleView.layer.shouldRasterize = YES; 54 | } 55 | 56 | { 57 | _dotView = [UIView new]; 58 | [self addSubview:_dotView]; 59 | 60 | _dotView.backgroundColor = [UIColor redColor]; 61 | _dotView.hidden = YES; 62 | 63 | _dotView.layer.rasterizationScale = [UIScreen mainScreen].scale; 64 | _dotView.layer.shouldRasterize = YES; 65 | } 66 | 67 | { 68 | _textLabel = [UILabel new]; 69 | [self addSubview:_textLabel]; 70 | 71 | _textLabel.textColor = [UIColor blackColor]; 72 | _textLabel.textAlignment = NSTextAlignmentCenter; 73 | _textLabel.font = [UIFont systemFontOfSize:[UIFont systemFontSize]]; 74 | } 75 | 76 | { 77 | UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTouch)]; 78 | 79 | self.userInteractionEnabled = YES; 80 | [self addGestureRecognizer:gesture]; 81 | } 82 | } 83 | 84 | - (void)layoutSubviews 85 | { 86 | [super layoutSubviews]; 87 | 88 | _textLabel.frame = self.bounds; 89 | 90 | CGFloat sizeCircle = MIN(self.frame.size.width, self.frame.size.height); 91 | CGFloat sizeDot = sizeCircle; 92 | 93 | sizeCircle = sizeCircle * _circleRatio; 94 | sizeDot = sizeDot * _dotRatio; 95 | 96 | sizeCircle = roundf(sizeCircle); 97 | sizeDot = roundf(sizeDot); 98 | 99 | _circleView.frame = CGRectMake(0, 0, sizeCircle, sizeCircle); 100 | _circleView.center = CGPointMake(self.frame.size.width / 2., self.frame.size.height / 2.); 101 | _circleView.layer.cornerRadius = sizeCircle / 2.; 102 | 103 | _dotView.frame = CGRectMake(0, 0, sizeDot, sizeDot); 104 | _dotView.center = CGPointMake(self.frame.size.width / 2., (self.frame.size.height / 2.) +sizeDot * 2.5); 105 | _dotView.layer.cornerRadius = sizeDot / 2.; 106 | } 107 | 108 | - (void)setDate:(NSDate *)date 109 | { 110 | NSAssert(date != nil, @"date cannot be nil"); 111 | NSAssert(_manager != nil, @"manager cannot be nil"); 112 | 113 | self->_date = date; 114 | [self reload]; 115 | } 116 | 117 | - (void)reload 118 | { 119 | static NSDateFormatter *dateFormatter = nil; 120 | if(!dateFormatter){ 121 | dateFormatter = [_manager.dateHelper createDateFormatter]; 122 | } 123 | [dateFormatter setDateFormat:self.dayFormat]; 124 | 125 | _textLabel.text = [ dateFormatter stringFromDate:_date]; 126 | [_manager.delegateManager prepareDayView:self]; 127 | } 128 | 129 | - (void)didTouch 130 | { 131 | [_manager.delegateManager didTouchDayView:self]; 132 | } 133 | 134 | - (NSString *)dayFormat 135 | { 136 | return self.manager.settings.zeroPaddedDayFormat ? @"dd" : @"d"; 137 | } 138 | 139 | @end 140 | -------------------------------------------------------------------------------- /JTCalendar/Views/JTCalendarMenuView.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarMenuView.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | #import "JTMenu.h" 11 | 12 | @interface JTCalendarMenuView : UIView 13 | 14 | @property (nonatomic, weak) JTCalendarManager *manager; 15 | 16 | @property (nonatomic) CGFloat contentRatio; 17 | 18 | @property (nonatomic, readonly) UIScrollView *scrollView; 19 | 20 | /*! 21 | * Must be call if override the class 22 | */ 23 | - (void)commonInit; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /JTCalendar/Views/JTCalendarMenuView.m: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarMenuView.m 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import "JTCalendarMenuView.h" 9 | 10 | #import "JTCalendarManager.h" 11 | 12 | typedef NS_ENUM(NSInteger, JTCalendarPageMode) { 13 | JTCalendarPageModeFull, 14 | JTCalendarPageModeCenter, 15 | JTCalendarPageModeCenterLeft, 16 | JTCalendarPageModeCenterRight 17 | }; 18 | 19 | @interface JTCalendarMenuView (){ 20 | CGSize _lastSize; 21 | 22 | UIView *_leftView; 23 | UIView *_centerView; 24 | UIView *_rightView; 25 | 26 | JTCalendarPageMode _pageMode; 27 | } 28 | 29 | @end 30 | 31 | @implementation JTCalendarMenuView 32 | 33 | - (instancetype)initWithFrame:(CGRect)frame 34 | { 35 | self = [super initWithFrame:frame]; 36 | if(!self){ 37 | return nil; 38 | } 39 | 40 | [self commonInit]; 41 | 42 | return self; 43 | } 44 | 45 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 46 | { 47 | self = [super initWithCoder:aDecoder]; 48 | if(!self){ 49 | return nil; 50 | } 51 | 52 | [self commonInit]; 53 | 54 | return self; 55 | } 56 | 57 | - (void)commonInit 58 | { 59 | self.clipsToBounds = YES; 60 | 61 | _contentRatio = 1.; 62 | 63 | { 64 | _scrollView = [UIScrollView new]; 65 | [self addSubview:_scrollView]; 66 | 67 | _scrollView.showsHorizontalScrollIndicator = NO; 68 | _scrollView.showsVerticalScrollIndicator = NO; 69 | _scrollView.pagingEnabled = YES; 70 | _scrollView.delegate = self; 71 | 72 | _scrollView.clipsToBounds = NO; 73 | } 74 | } 75 | 76 | - (void)layoutSubviews 77 | { 78 | [super layoutSubviews]; 79 | [self resizeViewsIfWidthChanged]; 80 | } 81 | 82 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView 83 | { 84 | if(_scrollView.contentSize.width <= 0){ 85 | return; 86 | } 87 | 88 | [_manager.scrollManager updateHorizontalContentOffset:(_scrollView.contentOffset.x / _scrollView.contentSize.width)]; 89 | } 90 | 91 | - (void)resizeViewsIfWidthChanged 92 | { 93 | CGSize size = self.frame.size; 94 | if(size.width != _lastSize.width){ 95 | _lastSize = size; 96 | 97 | [self repositionViews]; 98 | } 99 | else if(size.height != _lastSize.height){ 100 | _lastSize = size; 101 | 102 | _scrollView.frame = CGRectMake(_scrollView.frame.origin.x, 0, _scrollView.frame.size.width, size.height); 103 | _scrollView.contentSize = CGSizeMake(_scrollView.contentSize.width, size.height); 104 | 105 | _leftView.frame = CGRectMake(_leftView.frame.origin.x, 0, _scrollView.frame.size.width, size.height); 106 | _centerView.frame = CGRectMake(_centerView.frame.origin.x, 0, _scrollView.frame.size.width, size.height); 107 | _rightView.frame = CGRectMake(_rightView.frame.origin.x, 0, _scrollView.frame.size.width, size.height); 108 | } 109 | } 110 | 111 | - (void)repositionViews 112 | { 113 | // Avoid vertical scrolling when the view is in a UINavigationController 114 | _scrollView.contentInset = UIEdgeInsetsZero; 115 | 116 | { 117 | CGFloat width = self.frame.size.width * _contentRatio; 118 | CGFloat x = (self.frame.size.width - width) / 2.; 119 | CGFloat height = self.frame.size.height; 120 | 121 | _scrollView.frame = CGRectMake(x, 0, width, height); 122 | _scrollView.contentSize = CGSizeMake(width, height); 123 | } 124 | 125 | CGSize size = _scrollView.frame.size; 126 | 127 | switch (_pageMode) { 128 | case JTCalendarPageModeFull: 129 | _scrollView.contentSize = CGSizeMake(size.width * 3, size.height); 130 | 131 | _leftView.frame = CGRectMake(0, 0, size.width, size.height); 132 | _centerView.frame = CGRectMake(size.width, 0, size.width, size.height); 133 | _rightView.frame = CGRectMake(size.width * 2, 0, size.width, size.height); 134 | 135 | _scrollView.contentOffset = CGPointMake(size.width, 0); 136 | break; 137 | case JTCalendarPageModeCenter: 138 | _scrollView.contentSize = size; 139 | 140 | _leftView.frame = CGRectMake(- size.width, 0, size.width, size.height); 141 | _centerView.frame = CGRectMake(0, 0, size.width, size.height); 142 | _rightView.frame = CGRectMake(size.width, 0, size.width, size.height); 143 | 144 | _scrollView.contentOffset = CGPointZero; 145 | break; 146 | case JTCalendarPageModeCenterLeft: 147 | _scrollView.contentSize = CGSizeMake(size.width * 2, size.height); 148 | 149 | _leftView.frame = CGRectMake(0, 0, size.width, size.height); 150 | _centerView.frame = CGRectMake(size.width, 0, size.width, size.height); 151 | _rightView.frame = CGRectMake(size.width * 2, 0, size.width, size.height); 152 | 153 | _scrollView.contentOffset = CGPointMake(size.width, 0); 154 | break; 155 | case JTCalendarPageModeCenterRight: 156 | _scrollView.contentSize = CGSizeMake(size.width * 2, size.height); 157 | 158 | _leftView.frame = CGRectMake(- size.width, 0, size.width, size.height); 159 | _centerView.frame = CGRectMake(0, 0, size.width, size.height); 160 | _rightView.frame = CGRectMake(size.width, 0, size.width, size.height); 161 | 162 | _scrollView.contentOffset = CGPointZero; 163 | break; 164 | } 165 | } 166 | 167 | - (void)setPreviousDate:(NSDate *)previousDate 168 | currentDate:(NSDate *)currentDate 169 | nextDate:(NSDate *)nextDate 170 | { 171 | NSAssert(currentDate != nil, @"currentDate cannot be nil"); 172 | NSAssert(_manager != nil, @"manager cannot be nil"); 173 | 174 | if(!_leftView){ 175 | _leftView = [_manager.delegateManager buildMenuItemView]; 176 | [_scrollView addSubview:_leftView]; 177 | 178 | _centerView = [_manager.delegateManager buildMenuItemView]; 179 | [_scrollView addSubview:_centerView]; 180 | 181 | _rightView = [_manager.delegateManager buildMenuItemView]; 182 | [_scrollView addSubview:_rightView]; 183 | } 184 | 185 | [_manager.delegateManager prepareMenuItemView:_leftView date:previousDate]; 186 | [_manager.delegateManager prepareMenuItemView:_centerView date:currentDate]; 187 | [_manager.delegateManager prepareMenuItemView:_rightView date:nextDate]; 188 | 189 | BOOL haveLeftPage = [_manager.delegateManager canDisplayPageWithDate:previousDate]; 190 | BOOL haveRightPage = [_manager.delegateManager canDisplayPageWithDate:nextDate]; 191 | 192 | if(_manager.settings.pageViewHideWhenPossible){ 193 | _leftView.hidden = !haveLeftPage; 194 | _rightView.hidden = !haveRightPage; 195 | } 196 | else{ 197 | _leftView.hidden = NO; 198 | _rightView.hidden = NO; 199 | } 200 | } 201 | 202 | - (void)updatePageMode:(NSUInteger)pageMode 203 | { 204 | if(_pageMode == pageMode){ 205 | return; 206 | } 207 | 208 | _pageMode = pageMode; 209 | [self repositionViews]; 210 | } 211 | 212 | @end 213 | -------------------------------------------------------------------------------- /JTCalendar/Views/JTCalendarPageView.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarPageView.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | #import "JTCalendarPage.h" 11 | 12 | @interface JTCalendarPageView : UIView 13 | 14 | @property (nonatomic, weak) JTCalendarManager *manager; 15 | 16 | @property (nonatomic) NSDate *date; 17 | 18 | /*! 19 | * Must be call if override the class 20 | */ 21 | - (void)commonInit; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /JTCalendar/Views/JTCalendarPageView.m: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarPageView.m 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import "JTCalendarPageView.h" 9 | 10 | #import "JTCalendarManager.h" 11 | 12 | #define MAX_WEEKS_BY_MONTH 6 13 | 14 | @interface JTCalendarPageView (){ 15 | UIView *_weekDayView; 16 | NSMutableArray *_weeksViews; 17 | NSUInteger _numberOfWeeksDisplayed; 18 | } 19 | 20 | @end 21 | 22 | @implementation JTCalendarPageView 23 | 24 | - (instancetype)initWithFrame:(CGRect)frame 25 | { 26 | self = [super initWithFrame:frame]; 27 | if(!self){ 28 | return nil; 29 | } 30 | 31 | [self commonInit]; 32 | 33 | return self; 34 | } 35 | 36 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 37 | { 38 | self = [super initWithCoder:aDecoder]; 39 | if(!self){ 40 | return nil; 41 | } 42 | 43 | [self commonInit]; 44 | 45 | return self; 46 | } 47 | 48 | - (void)commonInit 49 | { 50 | // Maybe used in future 51 | } 52 | 53 | - (void)setDate:(NSDate *)date 54 | { 55 | NSAssert(_manager != nil, @"manager cannot be nil"); 56 | NSAssert(date != nil, @"date cannot be nil"); 57 | 58 | self->_date = date; 59 | 60 | [self reload]; 61 | } 62 | 63 | - (void)reload 64 | { 65 | if(_manager.settings.pageViewHaveWeekDaysView && !_weekDayView){ 66 | _weekDayView = [_manager.delegateManager buildWeekDayView]; 67 | [self addSubview:_weekDayView]; 68 | } 69 | _weekDayView.manager = _manager; 70 | [_weekDayView reload]; 71 | 72 | if(!_weeksViews){ 73 | _weeksViews = [NSMutableArray new]; 74 | 75 | for(int i = 0; i < MAX_WEEKS_BY_MONTH; ++i){ 76 | UIView *weekView = [_manager.delegateManager buildWeekView]; 77 | [_weeksViews addObject:weekView]; 78 | [self addSubview:weekView]; 79 | 80 | weekView.manager = _manager; 81 | } 82 | } 83 | 84 | NSDate *weekDate = nil; 85 | 86 | if(_manager.settings.weekModeEnabled){ 87 | _numberOfWeeksDisplayed = MIN(MAX(_manager.settings.pageViewWeekModeNumberOfWeeks, 1), MAX_WEEKS_BY_MONTH); 88 | weekDate = [_manager.dateHelper firstWeekDayOfWeek:_date]; 89 | } 90 | else{ 91 | _numberOfWeeksDisplayed = MIN(_manager.settings.pageViewNumberOfWeeks, MAX_WEEKS_BY_MONTH); 92 | if(_numberOfWeeksDisplayed == 0){ 93 | _numberOfWeeksDisplayed = [_manager.dateHelper numberOfWeeks:_date]; 94 | } 95 | 96 | weekDate = [_manager.dateHelper firstWeekDayOfMonth:_date]; 97 | } 98 | 99 | for(NSUInteger i = 0; i < _numberOfWeeksDisplayed; i++){ 100 | UIView *weekView = _weeksViews[i]; 101 | 102 | weekView.hidden = NO; 103 | 104 | // Process the check on another month for the 1st, 4th and 5th weeks 105 | if(i == 0 || i >= 4){ 106 | [weekView setStartDate:weekDate updateAnotherMonth:YES monthDate:_date]; 107 | } 108 | else{ 109 | [weekView setStartDate:weekDate updateAnotherMonth:NO monthDate:_date]; 110 | } 111 | 112 | weekDate = [_manager.dateHelper addToDate:weekDate weeks:1]; 113 | } 114 | 115 | for(NSUInteger i = _numberOfWeeksDisplayed; i < MAX_WEEKS_BY_MONTH; i++){ 116 | UIView *weekView = _weeksViews[i]; 117 | 118 | weekView.hidden = YES; 119 | } 120 | 121 | /* 122 | * Forces the view to re-render the height of each weekView 123 | * adjusted for the new `_numberOfWeeksDisplayed` 124 | */ 125 | [self setNeedsLayout]; 126 | } 127 | 128 | - (void)layoutSubviews 129 | { 130 | [super layoutSubviews]; 131 | 132 | if(!_weeksViews){ 133 | return; 134 | } 135 | 136 | CGFloat y = 0; 137 | CGFloat weekWidth = self.frame.size.width; 138 | 139 | if(_manager.settings.pageViewHaveWeekDaysView){ 140 | CGFloat weekDayHeight = _weekDayView.frame.size.height; // Force use default height 141 | 142 | // Or use the same height than weeksViews 143 | if(weekDayHeight == 0 || _manager.settings.pageViewWeekDaysViewAutomaticHeight){ 144 | weekDayHeight = self.frame.size.height / (_numberOfWeeksDisplayed + 1); 145 | } 146 | 147 | _weekDayView.frame = CGRectMake(0, 0, weekWidth, weekDayHeight); 148 | y = weekDayHeight; 149 | } 150 | 151 | CGFloat weekHeight = (self.frame.size.height - y) / _numberOfWeeksDisplayed; 152 | 153 | for(UIView *weekView in _weeksViews){ 154 | weekView.frame = CGRectMake(0, y, weekWidth, weekHeight); 155 | y += weekHeight; 156 | } 157 | } 158 | 159 | @end 160 | -------------------------------------------------------------------------------- /JTCalendar/Views/JTCalendarWeekDayView.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarWeekDayView.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | #import "JTCalendarWeekDay.h" 11 | 12 | @interface JTCalendarWeekDayView : UIView 13 | 14 | @property (nonatomic, weak) JTCalendarManager *manager; 15 | 16 | @property (nonatomic, readonly) NSArray *dayViews; 17 | 18 | /*! 19 | * Must be call if override the class 20 | */ 21 | - (void)commonInit; 22 | 23 | /*! 24 | * Rebuild the view, must be call if you change `weekDayFormat` or `firstWeekday` 25 | */ 26 | - (void)reload; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /JTCalendar/Views/JTCalendarWeekDayView.m: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarWeekDayView.m 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import "JTCalendarWeekDayView.h" 9 | 10 | #import "JTCalendarManager.h" 11 | 12 | #define NUMBER_OF_DAY_BY_WEEK 7. 13 | 14 | @implementation JTCalendarWeekDayView 15 | 16 | - (instancetype)initWithFrame:(CGRect)frame 17 | { 18 | self = [super initWithFrame:frame]; 19 | if(!self){ 20 | return nil; 21 | } 22 | 23 | [self commonInit]; 24 | 25 | return self; 26 | } 27 | 28 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 29 | { 30 | self = [super initWithCoder:aDecoder]; 31 | if(!self){ 32 | return nil; 33 | } 34 | 35 | [self commonInit]; 36 | 37 | return self; 38 | } 39 | 40 | - (void)commonInit 41 | { 42 | NSMutableArray *dayViews = [NSMutableArray new]; 43 | 44 | for(int i = 0; i < NUMBER_OF_DAY_BY_WEEK; ++i){ 45 | UILabel *label = [UILabel new]; 46 | [self addSubview:label]; 47 | [dayViews addObject:label]; 48 | 49 | label.textAlignment = NSTextAlignmentCenter; 50 | label.textColor = [UIColor colorWithRed:152./256. green:147./256. blue:157./256. alpha:1.]; 51 | label.font = [UIFont systemFontOfSize:11]; 52 | } 53 | 54 | _dayViews = dayViews; 55 | } 56 | 57 | - (void)reload 58 | { 59 | NSAssert(_manager != nil, @"manager cannot be nil"); 60 | 61 | NSDateFormatter *dateFormatter = [_manager.dateHelper createDateFormatter]; 62 | NSMutableArray *days = nil; 63 | 64 | dateFormatter.timeZone = _manager.dateHelper.calendar.timeZone; 65 | dateFormatter.locale = _manager.dateHelper.calendar.locale; 66 | 67 | switch(_manager.settings.weekDayFormat) { 68 | case JTCalendarWeekDayFormatSingle: 69 | days = [[dateFormatter veryShortStandaloneWeekdaySymbols] mutableCopy]; 70 | break; 71 | case JTCalendarWeekDayFormatShort: 72 | days = [[dateFormatter shortStandaloneWeekdaySymbols] mutableCopy]; 73 | break; 74 | case JTCalendarWeekDayFormatFull: 75 | days = [[dateFormatter standaloneWeekdaySymbols] mutableCopy]; 76 | break; 77 | } 78 | 79 | for(NSInteger i = 0; i < days.count; ++i){ 80 | NSString *day = days[i]; 81 | [days replaceObjectAtIndex:i withObject:[day uppercaseString]]; 82 | } 83 | 84 | // Redorder days for be conform to calendar 85 | { 86 | NSCalendar *calendar = [_manager.dateHelper calendar]; 87 | NSUInteger firstWeekday = (calendar.firstWeekday + 6) % 7; // Sunday == 1, Saturday == 7 88 | 89 | for(int i = 0; i < firstWeekday; ++i){ 90 | id day = [days firstObject]; 91 | [days removeObjectAtIndex:0]; 92 | [days addObject:day]; 93 | } 94 | } 95 | 96 | for(int i = 0; i < NUMBER_OF_DAY_BY_WEEK; ++i){ 97 | UILabel *label = _dayViews[i]; 98 | label.text = days[i]; 99 | } 100 | } 101 | 102 | - (void)layoutSubviews 103 | { 104 | [super layoutSubviews]; 105 | 106 | if(!_dayViews){ 107 | return; 108 | } 109 | 110 | CGFloat x = 0; 111 | CGFloat dayWidth = self.frame.size.width / NUMBER_OF_DAY_BY_WEEK; 112 | CGFloat dayHeight = self.frame.size.height; 113 | 114 | for(UIView *dayView in _dayViews){ 115 | dayView.frame = CGRectMake(x, 0, ceil(dayWidth), ceil(dayHeight)); 116 | x += dayWidth; 117 | } 118 | } 119 | 120 | @end 121 | -------------------------------------------------------------------------------- /JTCalendar/Views/JTCalendarWeekView.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarWeekView.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | #import "JTCalendarWeek.h" 11 | 12 | @interface JTCalendarWeekView : UIView 13 | 14 | @property (nonatomic, weak) JTCalendarManager *manager; 15 | 16 | @property (nonatomic, readonly) NSDate *startDate; 17 | 18 | /*! 19 | * Must be call if override the class 20 | */ 21 | - (void)commonInit; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /JTCalendar/Views/JTCalendarWeekView.m: -------------------------------------------------------------------------------- 1 | // 2 | // JTCalendarWeekView.m 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import "JTCalendarWeekView.h" 9 | 10 | #import "JTCalendarManager.h" 11 | 12 | #define NUMBER_OF_DAY_BY_WEEK 7. 13 | 14 | @interface JTCalendarWeekView (){ 15 | NSMutableArray *_daysViews; 16 | } 17 | 18 | @end 19 | 20 | @implementation JTCalendarWeekView 21 | 22 | - (instancetype)initWithFrame:(CGRect)frame 23 | { 24 | self = [super initWithFrame:frame]; 25 | if(!self){ 26 | return nil; 27 | } 28 | 29 | [self commonInit]; 30 | 31 | return self; 32 | } 33 | 34 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 35 | { 36 | self = [super initWithCoder:aDecoder]; 37 | if(!self){ 38 | return nil; 39 | } 40 | 41 | [self commonInit]; 42 | 43 | return self; 44 | } 45 | 46 | - (void)commonInit 47 | { 48 | // Maybe used in future 49 | } 50 | 51 | - (void)setStartDate:(NSDate *)startDate updateAnotherMonth:(BOOL)enable monthDate:(NSDate *)monthDate 52 | { 53 | NSAssert(startDate != nil, @"startDate cannot be nil"); 54 | NSAssert(_manager != nil, @"manager cannot be nil"); 55 | if(enable){ 56 | NSAssert(monthDate != nil, @"monthDate cannot be nil"); 57 | } 58 | 59 | self->_startDate = startDate; 60 | 61 | [self createDayViews]; 62 | [self reloadAndUpdateAnotherMonth:enable monthDate:monthDate]; 63 | } 64 | 65 | - (void)reloadAndUpdateAnotherMonth:(BOOL)enable monthDate:(NSDate *)monthDate 66 | { 67 | NSDate *dayDate = _startDate; 68 | 69 | for(UIView *dayView in _daysViews){ 70 | // Must done before setDate to dayView for `prepareDayView` method 71 | if(!enable){ 72 | [dayView setIsFromAnotherMonth:NO]; 73 | } 74 | else{ 75 | if([_manager.dateHelper date:dayDate isTheSameMonthThan:monthDate]){ 76 | [dayView setIsFromAnotherMonth:NO]; 77 | } 78 | else{ 79 | [dayView setIsFromAnotherMonth:YES]; 80 | } 81 | } 82 | 83 | dayView.date = dayDate; 84 | dayDate = [_manager.dateHelper addToDate:dayDate days:1]; 85 | } 86 | } 87 | 88 | - (void)createDayViews 89 | { 90 | if(!_daysViews){ 91 | _daysViews = [NSMutableArray new]; 92 | 93 | for(int i = 0; i < NUMBER_OF_DAY_BY_WEEK; ++i){ 94 | UIView *dayView = [_manager.delegateManager buildDayView]; 95 | [_daysViews addObject:dayView]; 96 | [self addSubview:dayView]; 97 | 98 | dayView.manager = _manager; 99 | } 100 | } 101 | } 102 | 103 | - (void)layoutSubviews 104 | { 105 | [super layoutSubviews]; 106 | 107 | if(!_daysViews){ 108 | return; 109 | } 110 | 111 | CGFloat x = 0; 112 | CGFloat dayWidth = self.frame.size.width / NUMBER_OF_DAY_BY_WEEK; 113 | CGFloat dayHeight = self.frame.size.height; 114 | 115 | for(UIView *dayView in _daysViews){ 116 | dayView.frame = CGRectMake(x, 0, dayWidth, dayHeight); 117 | x += dayWidth; 118 | } 119 | } 120 | 121 | @end 122 | -------------------------------------------------------------------------------- /JTCalendar/Views/JTHorizontalCalendarView.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTHorizontalCalendar.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | #import "JTContent.h" 11 | 12 | @interface JTHorizontalCalendarView : UIScrollView 13 | 14 | @property (nonatomic, weak) JTCalendarManager *manager; 15 | 16 | @property (nonatomic) NSDate *date; 17 | 18 | /*! 19 | * Must be call if override the class 20 | */ 21 | - (void)commonInit; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /JTCalendar/Views/JTHorizontalCalendarView.m: -------------------------------------------------------------------------------- 1 | // 2 | // JTHorizontalCalendar.m 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import "JTHorizontalCalendarView.h" 9 | 10 | #import "JTCalendarManager.h" 11 | 12 | typedef NS_ENUM(NSInteger, JTCalendarPageMode) { 13 | JTCalendarPageModeFull, 14 | JTCalendarPageModeCenter, 15 | JTCalendarPageModeCenterLeft, 16 | JTCalendarPageModeCenterRight 17 | }; 18 | 19 | @interface JTHorizontalCalendarView (){ 20 | CGSize _lastSize; 21 | 22 | UIView *_leftView; 23 | UIView *_centerView; 24 | UIView *_rightView; 25 | 26 | JTCalendarPageMode _pageMode; 27 | } 28 | 29 | @end 30 | 31 | @implementation JTHorizontalCalendarView 32 | 33 | - (instancetype)initWithFrame:(CGRect)frame 34 | { 35 | self = [super initWithFrame:frame]; 36 | if(!self){ 37 | return nil; 38 | } 39 | 40 | [self commonInit]; 41 | 42 | return self; 43 | } 44 | 45 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 46 | { 47 | self = [super initWithCoder:aDecoder]; 48 | if(!self){ 49 | return nil; 50 | } 51 | 52 | [self commonInit]; 53 | 54 | return self; 55 | } 56 | 57 | - (void)commonInit 58 | { 59 | self.showsHorizontalScrollIndicator = NO; 60 | self.showsVerticalScrollIndicator = NO; 61 | self.pagingEnabled = YES; 62 | self.clipsToBounds = YES; 63 | } 64 | 65 | - (void)layoutSubviews 66 | { 67 | [self resizeViewsIfWidthChanged]; 68 | [self viewDidScroll]; 69 | } 70 | 71 | - (void)resizeViewsIfWidthChanged 72 | { 73 | CGSize size = self.frame.size; 74 | if(size.width != _lastSize.width){ 75 | _lastSize = size; 76 | 77 | [self repositionViews]; 78 | } 79 | else if(size.height != _lastSize.height){ 80 | _lastSize = size; 81 | 82 | _leftView.frame = CGRectMake(_leftView.frame.origin.x, 0, size.width, size.height); 83 | _centerView.frame = CGRectMake(_centerView.frame.origin.x, 0, size.width, size.height); 84 | _rightView.frame = CGRectMake(_rightView.frame.origin.x, 0, size.width, size.height); 85 | 86 | self.contentSize = CGSizeMake(self.contentSize.width, size.height); 87 | } 88 | } 89 | 90 | - (void)viewDidScroll 91 | { 92 | if(self.contentSize.width <= 0){ 93 | return; 94 | } 95 | 96 | CGSize size = self.frame.size; 97 | 98 | switch (_pageMode) { 99 | case JTCalendarPageModeFull: 100 | 101 | if(self.contentOffset.x < size.width / 2.){ 102 | [self loadPreviousPage]; 103 | } 104 | else if(self.contentOffset.x > size.width * 1.5){ 105 | [self loadNextPage]; 106 | } 107 | 108 | break; 109 | case JTCalendarPageModeCenter: 110 | 111 | break; 112 | case JTCalendarPageModeCenterLeft: 113 | 114 | if(self.contentOffset.x < size.width / 2.){ 115 | [self loadPreviousPage]; 116 | } 117 | 118 | break; 119 | case JTCalendarPageModeCenterRight: 120 | 121 | if(self.contentOffset.x > size.width / 2.){ 122 | [self loadNextPage]; 123 | } 124 | 125 | break; 126 | } 127 | 128 | [_manager.scrollManager updateMenuContentOffset:(self.contentOffset.x / self.contentSize.width) pageMode:_pageMode]; 129 | } 130 | 131 | - (void)loadPreviousPageWithAnimation 132 | { 133 | switch (_pageMode) { 134 | case JTCalendarPageModeCenterRight: 135 | case JTCalendarPageModeCenter: 136 | return; 137 | default: 138 | break; 139 | } 140 | 141 | CGSize size = self.frame.size; 142 | CGPoint point = CGPointMake(self.contentOffset.x - size.width, 0); 143 | [self setContentOffset:point animated:YES]; 144 | } 145 | 146 | - (void)loadNextPageWithAnimation 147 | { 148 | switch (_pageMode) { 149 | case JTCalendarPageModeCenterLeft: 150 | case JTCalendarPageModeCenter: 151 | return; 152 | default: 153 | break; 154 | } 155 | 156 | CGSize size = self.frame.size; 157 | CGPoint point = CGPointMake(self.contentOffset.x + size.width, 0); 158 | [self setContentOffset:point animated:YES]; 159 | } 160 | 161 | - (void)loadPreviousPage 162 | { 163 | NSDate *nextDate = [_manager.delegateManager dateForPreviousPageWithCurrentDate:_leftView.date]; 164 | 165 | // Must be set before chaging date for PageView for updating day views 166 | self->_date = _leftView.date; 167 | 168 | UIView *tmpView = _rightView; 169 | 170 | _rightView = _centerView; 171 | _centerView = _leftView; 172 | 173 | _leftView = tmpView; 174 | _leftView.date = nextDate; 175 | 176 | [self updateMenuDates]; 177 | 178 | JTCalendarPageMode previousPageMode = _pageMode; 179 | 180 | [self updatePageMode]; 181 | 182 | CGSize size = self.frame.size; 183 | 184 | switch (_pageMode) { 185 | case JTCalendarPageModeFull: 186 | 187 | _leftView.frame = CGRectMake(0, 0, size.width, size.height); 188 | _centerView.frame = CGRectMake(size.width, 0, size.width, size.height); 189 | _rightView.frame = CGRectMake(size.width * 2, 0, size.width, size.height); 190 | 191 | if(previousPageMode == JTCalendarPageModeFull){ 192 | self.contentOffset = CGPointMake(self.contentOffset.x + size.width, 0); 193 | } 194 | else if(previousPageMode == JTCalendarPageModeCenterLeft){ 195 | self.contentOffset = CGPointMake(self.contentOffset.x + size.width, 0); 196 | } 197 | 198 | self.contentSize = CGSizeMake(size.width * 3, size.height); 199 | 200 | break; 201 | case JTCalendarPageModeCenter: 202 | // Not tested 203 | 204 | _leftView.frame = CGRectMake(- size.width, 0, size.width, size.height); 205 | _centerView.frame = CGRectMake(0, 0, size.width, size.height); 206 | _rightView.frame = CGRectMake(size.width, 0, size.width, size.height); 207 | 208 | self.contentSize = size; 209 | 210 | break; 211 | case JTCalendarPageModeCenterLeft: 212 | 213 | _leftView.frame = CGRectMake(0, 0, size.width, size.height); 214 | _centerView.frame = CGRectMake(size.width, 0, size.width, size.height); 215 | _rightView.frame = CGRectMake(size.width * 2, 0, size.width, size.height); 216 | 217 | self.contentOffset = CGPointMake(self.contentOffset.x + size.width, 0); 218 | self.contentSize = CGSizeMake(size.width * 2, size.height); 219 | 220 | break; 221 | case JTCalendarPageModeCenterRight: 222 | 223 | _leftView.frame = CGRectMake(- size.width, 0, size.width, size.height); 224 | _centerView.frame = CGRectMake(0, 0, size.width, size.height); 225 | _rightView.frame = CGRectMake(size.width, 0, size.width, size.height); 226 | 227 | self.contentSize = CGSizeMake(size.width * 2, size.height); 228 | 229 | break; 230 | } 231 | 232 | // Update dayViews becuase current month changed 233 | [_rightView reload]; 234 | [_centerView reload]; 235 | 236 | if(_manager.delegate && [_manager.delegate respondsToSelector:@selector(calendarDidLoadPreviousPage:)]){ 237 | [_manager.delegate calendarDidLoadPreviousPage:_manager]; 238 | } 239 | } 240 | 241 | - (void)loadNextPage 242 | { 243 | NSDate *nextDate = [_manager.delegateManager dateForNextPageWithCurrentDate:_rightView.date]; 244 | 245 | // Must be set before chaging date for PageView for updating day views 246 | self->_date = _rightView.date; 247 | 248 | UIView *tmpView = _leftView; 249 | 250 | _leftView = _centerView; 251 | _centerView = _rightView; 252 | 253 | _rightView = tmpView; 254 | _rightView.date = nextDate; 255 | 256 | [self updateMenuDates]; 257 | 258 | JTCalendarPageMode previousPageMode = _pageMode; 259 | 260 | [self updatePageMode]; 261 | 262 | CGSize size = self.frame.size; 263 | 264 | switch (_pageMode) { 265 | case JTCalendarPageModeFull: 266 | 267 | _leftView.frame = CGRectMake(0, 0, size.width, size.height); 268 | _centerView.frame = CGRectMake(size.width, 0, size.width, size.height); 269 | _rightView.frame = CGRectMake(size.width * 2, 0, size.width, size.height); 270 | 271 | if(previousPageMode == JTCalendarPageModeFull){ 272 | self.contentOffset = CGPointMake(self.contentOffset.x - size.width, 0); 273 | } 274 | self.contentSize = CGSizeMake(size.width * 3, size.height); 275 | 276 | break; 277 | case JTCalendarPageModeCenter: 278 | // Not tested 279 | 280 | _leftView.frame = CGRectMake(- size.width, 0, size.width, size.height); 281 | _centerView.frame = CGRectMake(0, 0, size.width, size.height); 282 | _rightView.frame = CGRectMake(size.width, 0, size.width, size.height); 283 | 284 | self.contentSize = size; 285 | 286 | break; 287 | case JTCalendarPageModeCenterLeft: 288 | 289 | _leftView.frame = CGRectMake(0, 0, size.width, size.height); 290 | _centerView.frame = CGRectMake(size.width, 0, size.width, size.height); 291 | _rightView.frame = CGRectMake(size.width * 2, 0, size.width, size.height); 292 | 293 | if(previousPageMode != JTCalendarPageModeCenterRight){ 294 | self.contentOffset = CGPointMake(self.contentOffset.x - size.width, 0); 295 | } 296 | 297 | // Must be set a the end else the scroll freeze 298 | self.contentSize = CGSizeMake(size.width * 2, size.height); 299 | 300 | break; 301 | case JTCalendarPageModeCenterRight: 302 | // Not tested 303 | 304 | _leftView.frame = CGRectMake(- size.width, 0, size.width, size.height); 305 | _centerView.frame = CGRectMake(0, 0, size.width, size.height); 306 | _rightView.frame = CGRectMake(size.width, 0, size.width, size.height); 307 | 308 | self.contentSize = CGSizeMake(size.width * 2, size.height); 309 | 310 | break; 311 | } 312 | 313 | // Update dayViews becuase current month changed 314 | [_leftView reload]; 315 | [_centerView reload]; 316 | 317 | if(_manager.delegate && [_manager.delegate respondsToSelector:@selector(calendarDidLoadNextPage:)]){ 318 | [_manager.delegate calendarDidLoadNextPage:_manager]; 319 | } 320 | } 321 | 322 | - (void)setDate:(NSDate *)date 323 | { 324 | NSAssert(date != nil, @"date cannot be nil"); 325 | NSAssert(_manager != nil, @"manager cannot be nil"); 326 | 327 | self->_date = date; 328 | 329 | if(!_leftView){ 330 | _leftView = [_manager.delegateManager buildPageView]; 331 | [self addSubview:_leftView]; 332 | 333 | _centerView = [_manager.delegateManager buildPageView]; 334 | [self addSubview:_centerView]; 335 | 336 | _rightView = [_manager.delegateManager buildPageView]; 337 | [self addSubview:_rightView]; 338 | 339 | [self updateManagerForViews]; 340 | } 341 | 342 | _leftView.date = [_manager.delegateManager dateForPreviousPageWithCurrentDate:date]; 343 | _centerView.date = date; 344 | _rightView.date = [_manager.delegateManager dateForNextPageWithCurrentDate:date]; 345 | 346 | [self updateMenuDates]; 347 | 348 | [self updatePageMode]; 349 | [self repositionViews]; 350 | } 351 | 352 | - (void)setManager:(JTCalendarManager *)manager 353 | { 354 | self->_manager = manager; 355 | [self updateManagerForViews]; 356 | } 357 | 358 | - (void)updateManagerForViews 359 | { 360 | if(!_manager || !_leftView){ 361 | return; 362 | } 363 | 364 | _leftView.manager = _manager; 365 | _centerView.manager = _manager; 366 | _rightView.manager = _manager; 367 | } 368 | 369 | - (void)updatePageMode 370 | { 371 | BOOL haveLeftPage = [_manager.delegateManager canDisplayPageWithDate:_leftView.date]; 372 | BOOL haveRightPage = [_manager.delegateManager canDisplayPageWithDate:_rightView.date]; 373 | 374 | if(haveLeftPage && haveRightPage){ 375 | _pageMode = JTCalendarPageModeFull; 376 | } 377 | else if(!haveLeftPage && !haveRightPage){ 378 | _pageMode = JTCalendarPageModeCenter; 379 | } 380 | else if(!haveLeftPage){ 381 | _pageMode = JTCalendarPageModeCenterRight; 382 | } 383 | else{ 384 | _pageMode = JTCalendarPageModeCenterLeft; 385 | } 386 | 387 | if(_manager.settings.pageViewHideWhenPossible){ 388 | _leftView.hidden = !haveLeftPage; 389 | _rightView.hidden = !haveRightPage; 390 | } 391 | else{ 392 | _leftView.hidden = NO; 393 | _rightView.hidden = NO; 394 | } 395 | } 396 | 397 | - (void)repositionViews 398 | { 399 | CGSize size = self.frame.size; 400 | self.contentInset = UIEdgeInsetsZero; 401 | 402 | switch (_pageMode) { 403 | case JTCalendarPageModeFull: 404 | self.contentSize = CGSizeMake(size.width * 3, size.height); 405 | 406 | _leftView.frame = CGRectMake(0, 0, size.width, size.height); 407 | _centerView.frame = CGRectMake(size.width, 0, size.width, size.height); 408 | _rightView.frame = CGRectMake(size.width * 2, 0, size.width, size.height); 409 | 410 | self.contentOffset = CGPointMake(size.width, 0); 411 | break; 412 | case JTCalendarPageModeCenter: 413 | self.contentSize = size; 414 | 415 | _leftView.frame = CGRectMake(- size.width, 0, size.width, size.height); 416 | _centerView.frame = CGRectMake(0, 0, size.width, size.height); 417 | _rightView.frame = CGRectMake(size.width, 0, size.width, size.height); 418 | 419 | self.contentOffset = CGPointZero; 420 | break; 421 | case JTCalendarPageModeCenterLeft: 422 | self.contentSize = CGSizeMake(size.width * 2, size.height); 423 | 424 | _leftView.frame = CGRectMake(0, 0, size.width, size.height); 425 | _centerView.frame = CGRectMake(size.width, 0, size.width, size.height); 426 | _rightView.frame = CGRectMake(size.width * 2, 0, size.width, size.height); 427 | 428 | self.contentOffset = CGPointMake(size.width, 0); 429 | break; 430 | case JTCalendarPageModeCenterRight: 431 | self.contentSize = CGSizeMake(size.width * 2, size.height); 432 | 433 | _leftView.frame = CGRectMake(- size.width, 0, size.width, size.height); 434 | _centerView.frame = CGRectMake(0, 0, size.width, size.height); 435 | _rightView.frame = CGRectMake(size.width, 0, size.width, size.height); 436 | 437 | self.contentOffset = CGPointZero; 438 | break; 439 | } 440 | } 441 | 442 | - (void)updateMenuDates 443 | { 444 | [_manager.scrollManager setMenuPreviousDate:_leftView.date 445 | currentDate:_centerView.date 446 | nextDate:_rightView.date]; 447 | } 448 | 449 | @end 450 | -------------------------------------------------------------------------------- /JTCalendar/Views/JTVerticalCalendarView.h: -------------------------------------------------------------------------------- 1 | // 2 | // JTVerticalCalendarView.h 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import 9 | 10 | #import "JTContent.h" 11 | 12 | @interface JTVerticalCalendarView : UIScrollView 13 | 14 | @property (nonatomic, weak) JTCalendarManager *manager; 15 | 16 | @property (nonatomic) NSDate *date; 17 | 18 | /*! 19 | * Must be call if override the class 20 | */ 21 | - (void)commonInit; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /JTCalendar/Views/JTVerticalCalendarView.m: -------------------------------------------------------------------------------- 1 | // 2 | // JTVerticalCalendarView.m 3 | // JTCalendar 4 | // 5 | // Created by Jonathan Tribouharet 6 | // 7 | 8 | #import "JTVerticalCalendarView.h" 9 | 10 | #import "JTCalendarManager.h" 11 | 12 | typedef NS_ENUM(NSInteger, JTCalendarPageMode) { 13 | JTCalendarPageModeFull, 14 | JTCalendarPageModeCenter, 15 | JTCalendarPageModeCenterLeft, 16 | JTCalendarPageModeCenterRight 17 | }; 18 | 19 | @interface JTVerticalCalendarView (){ 20 | CGSize _lastSize; 21 | 22 | UIView *_leftView; 23 | UIView *_centerView; 24 | UIView *_rightView; 25 | 26 | JTCalendarPageMode _pageMode; 27 | } 28 | 29 | @end 30 | 31 | @implementation JTVerticalCalendarView 32 | 33 | - (instancetype)initWithFrame:(CGRect)frame 34 | { 35 | self = [super initWithFrame:frame]; 36 | if(!self){ 37 | return nil; 38 | } 39 | 40 | [self commonInit]; 41 | 42 | return self; 43 | } 44 | 45 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 46 | { 47 | self = [super initWithCoder:aDecoder]; 48 | if(!self){ 49 | return nil; 50 | } 51 | 52 | [self commonInit]; 53 | 54 | return self; 55 | } 56 | 57 | - (void)commonInit 58 | { 59 | self.showsHorizontalScrollIndicator = NO; 60 | self.showsVerticalScrollIndicator = NO; 61 | self.pagingEnabled = YES; 62 | self.clipsToBounds = YES; 63 | } 64 | 65 | - (void)layoutSubviews 66 | { 67 | [self resizeViewsIfWidthChanged]; 68 | [self viewDidScroll]; 69 | } 70 | 71 | - (void)resizeViewsIfWidthChanged 72 | { 73 | CGSize size = self.frame.size; 74 | if(size.height != _lastSize.height){ 75 | _lastSize = size; 76 | 77 | [self repositionViews]; 78 | } 79 | else if(size.width != _lastSize.width){ 80 | _lastSize = size; 81 | 82 | _leftView.frame = CGRectMake(0, _leftView.frame.origin.y, size.width, size.height); 83 | _centerView.frame = CGRectMake(0, _centerView.frame.origin.y, size.width, size.height); 84 | _rightView.frame = CGRectMake(0, _rightView.frame.origin.y, size.width, size.height); 85 | 86 | self.contentSize = CGSizeMake(size.width, self.contentSize.height); 87 | } 88 | } 89 | 90 | - (void)viewDidScroll 91 | { 92 | if(self.contentSize.height <= 0){ 93 | return; 94 | } 95 | 96 | CGSize size = self.frame.size; 97 | 98 | switch (_pageMode) { 99 | case JTCalendarPageModeFull: 100 | 101 | if(self.contentOffset.y < size.height / 2.){ 102 | [self loadPreviousPage]; 103 | } 104 | else if(self.contentOffset.y > size.height * 1.5){ 105 | [self loadNextPage]; 106 | } 107 | 108 | break; 109 | case JTCalendarPageModeCenter: 110 | 111 | break; 112 | case JTCalendarPageModeCenterLeft: 113 | 114 | if(self.contentOffset.y < size.height / 2.){ 115 | [self loadPreviousPage]; 116 | } 117 | 118 | break; 119 | case JTCalendarPageModeCenterRight: 120 | 121 | if(self.contentOffset.y > size.height / 2.){ 122 | [self loadNextPage]; 123 | } 124 | 125 | break; 126 | } 127 | 128 | [_manager.scrollManager updateMenuContentOffset:(self.contentOffset.y / self.contentSize.height) pageMode:_pageMode]; 129 | } 130 | 131 | - (void)loadPreviousPageWithAnimation 132 | { 133 | switch (_pageMode) { 134 | case JTCalendarPageModeCenterRight: 135 | case JTCalendarPageModeCenter: 136 | return; 137 | default: 138 | break; 139 | } 140 | 141 | CGSize size = self.frame.size; 142 | CGPoint point = CGPointMake(0, self.contentOffset.y - size.height); 143 | [self setContentOffset:point animated:YES]; 144 | } 145 | 146 | - (void)loadNextPageWithAnimation 147 | { 148 | switch (_pageMode) { 149 | case JTCalendarPageModeCenterLeft: 150 | case JTCalendarPageModeCenter: 151 | return; 152 | default: 153 | break; 154 | } 155 | 156 | CGSize size = self.frame.size; 157 | CGPoint point = CGPointMake(0, self.contentOffset.y + size.height); 158 | [self setContentOffset:point animated:YES]; 159 | } 160 | 161 | - (void)loadPreviousPage 162 | { 163 | NSDate *nextDate = [_manager.delegateManager dateForPreviousPageWithCurrentDate:_leftView.date]; 164 | 165 | // Must be set before chaging date for PageView for updating day views 166 | self->_date = _leftView.date; 167 | 168 | UIView *tmpView = _rightView; 169 | 170 | _rightView = _centerView; 171 | _centerView = _leftView; 172 | 173 | _leftView = tmpView; 174 | _leftView.date = nextDate; 175 | 176 | [self updateMenuDates]; 177 | 178 | JTCalendarPageMode previousPageMode = _pageMode; 179 | 180 | [self updatePageMode]; 181 | 182 | CGSize size = self.frame.size; 183 | 184 | switch (_pageMode) { 185 | case JTCalendarPageModeFull: 186 | 187 | _leftView.frame = CGRectMake(0, 0, size.width, size.height); 188 | _centerView.frame = CGRectMake(0, size.height, size.width, size.height); 189 | _rightView.frame = CGRectMake(0, size.height * 2, size.width, size.height); 190 | 191 | if(previousPageMode == JTCalendarPageModeFull){ 192 | self.contentOffset = CGPointMake(0, self.contentOffset.y + size.height); 193 | } 194 | else if(previousPageMode == JTCalendarPageModeCenterLeft){ 195 | self.contentOffset = CGPointMake(0, self.contentOffset.y + size.height); 196 | } 197 | 198 | self.contentSize = CGSizeMake(size.width, size.height * 3); 199 | 200 | break; 201 | case JTCalendarPageModeCenter: 202 | // Not tested 203 | 204 | _leftView.frame = CGRectMake(0, - size.height, size.width, size.height); 205 | _centerView.frame = CGRectMake(0, 0, size.width, size.height); 206 | _rightView.frame = CGRectMake(0, size.height, size.width, size.height); 207 | 208 | self.contentSize = size; 209 | 210 | break; 211 | case JTCalendarPageModeCenterLeft: 212 | 213 | _leftView.frame = CGRectMake(0, 0, size.width, size.height); 214 | _centerView.frame = CGRectMake(0, size.height, size.width, size.height); 215 | _rightView.frame = CGRectMake(0, size.height * 2, size.width, size.height); 216 | 217 | self.contentOffset = CGPointMake(0, self.contentOffset.y + size.height); 218 | self.contentSize = CGSizeMake(size.width, size.height * 2); 219 | 220 | break; 221 | case JTCalendarPageModeCenterRight: 222 | 223 | _leftView.frame = CGRectMake(0, - size.height, size.width, size.height); 224 | _centerView.frame = CGRectMake(0, 0, size.width, size.height); 225 | _rightView.frame = CGRectMake(0, size.height, size.width, size.height); 226 | 227 | self.contentSize = CGSizeMake(size.width, size.height * 2); 228 | 229 | break; 230 | } 231 | 232 | // Update subviews 233 | [_rightView reload]; 234 | [_centerView reload]; 235 | 236 | if(_manager.delegate && [_manager.delegate respondsToSelector:@selector(calendarDidLoadPreviousPage:)]){ 237 | [_manager.delegate calendarDidLoadPreviousPage:_manager]; 238 | } 239 | } 240 | 241 | - (void)loadNextPage 242 | { 243 | NSDate *nextDate = [_manager.delegateManager dateForNextPageWithCurrentDate:_rightView.date]; 244 | 245 | // Must be set before chaging date for PageView for updating day views 246 | self->_date = _rightView.date; 247 | 248 | UIView *tmpView = _leftView; 249 | 250 | _leftView = _centerView; 251 | _centerView = _rightView; 252 | 253 | _rightView = tmpView; 254 | _rightView.date = nextDate; 255 | 256 | [self updateMenuDates]; 257 | 258 | JTCalendarPageMode previousPageMode = _pageMode; 259 | 260 | [self updatePageMode]; 261 | 262 | CGSize size = self.frame.size; 263 | 264 | switch (_pageMode) { 265 | case JTCalendarPageModeFull: 266 | 267 | _leftView.frame = CGRectMake(0, 0, size.width, size.height); 268 | _centerView.frame = CGRectMake(0, size.height, size.width, size.height); 269 | _rightView.frame = CGRectMake(0, size.height * 2, size.width, size.height); 270 | 271 | if(previousPageMode == JTCalendarPageModeFull){ 272 | self.contentOffset = CGPointMake(0, self.contentOffset.y - size.height); 273 | } 274 | self.contentSize = CGSizeMake(size.width, size.height * 3); 275 | 276 | break; 277 | case JTCalendarPageModeCenter: 278 | // Not tested 279 | 280 | _leftView.frame = CGRectMake(0, - size.height, size.width, size.height); 281 | _centerView.frame = CGRectMake(0, 0, size.width, size.height); 282 | _rightView.frame = CGRectMake(0, size.height, size.width, size.height); 283 | 284 | self.contentSize = size; 285 | 286 | break; 287 | case JTCalendarPageModeCenterLeft: 288 | 289 | _leftView.frame = CGRectMake(0, 0, size.width, size.height); 290 | _centerView.frame = CGRectMake(0, size.height, size.width, size.height); 291 | _rightView.frame = CGRectMake(0, size.height * 2, size.width, size.height); 292 | 293 | if(previousPageMode != JTCalendarPageModeCenterRight){ 294 | // self.contentOffset = CGPointMake(0, self.contentOffset.x - size.width); 295 | } 296 | 297 | // Must be set a the end else the scroll freeze 298 | self.contentSize = CGSizeMake(size.width, size.height * 2); 299 | 300 | break; 301 | case JTCalendarPageModeCenterRight: 302 | // Not tested 303 | 304 | _leftView.frame = CGRectMake(0, - size.height, size.width, size.height); 305 | _centerView.frame = CGRectMake(0, 0, size.width, size.height); 306 | _rightView.frame = CGRectMake(0, size.height, size.width, size.height); 307 | 308 | self.contentSize = CGSizeMake(size.width, size.height * 2); 309 | 310 | break; 311 | } 312 | 313 | // Update subviews 314 | [_leftView reload]; 315 | [_centerView reload]; 316 | 317 | if(_manager.delegate && [_manager.delegate respondsToSelector:@selector(calendarDidLoadNextPage:)]){ 318 | [_manager.delegate calendarDidLoadNextPage:_manager]; 319 | } 320 | } 321 | 322 | - (void)setDate:(NSDate *)date 323 | { 324 | NSAssert(date != nil, @"date cannot be nil"); 325 | NSAssert(_manager != nil, @"manager cannot be nil"); 326 | 327 | self->_date = date; 328 | 329 | if(!_leftView){ 330 | _leftView = [_manager.delegateManager buildPageView]; 331 | [self addSubview:_leftView]; 332 | 333 | _centerView = [_manager.delegateManager buildPageView]; 334 | [self addSubview:_centerView]; 335 | 336 | _rightView = [_manager.delegateManager buildPageView]; 337 | [self addSubview:_rightView]; 338 | 339 | [self updateManagerForViews]; 340 | } 341 | 342 | _leftView.date = [_manager.delegateManager dateForPreviousPageWithCurrentDate:date]; 343 | _centerView.date = date; 344 | _rightView.date = [_manager.delegateManager dateForNextPageWithCurrentDate:date]; 345 | 346 | [self updateMenuDates]; 347 | 348 | [self updatePageMode]; 349 | [self repositionViews]; 350 | } 351 | 352 | - (void)setManager:(JTCalendarManager *)manager 353 | { 354 | self->_manager = manager; 355 | [self updateManagerForViews]; 356 | } 357 | 358 | - (void)updateManagerForViews 359 | { 360 | if(!_manager || !_leftView){ 361 | return; 362 | } 363 | 364 | _leftView.manager = _manager; 365 | _centerView.manager = _manager; 366 | _rightView.manager = _manager; 367 | } 368 | 369 | - (void)updatePageMode 370 | { 371 | BOOL haveLeftPage = [_manager.delegateManager canDisplayPageWithDate:_leftView.date]; 372 | BOOL haveRightPage = [_manager.delegateManager canDisplayPageWithDate:_rightView.date]; 373 | 374 | if(haveLeftPage && haveRightPage){ 375 | _pageMode = JTCalendarPageModeFull; 376 | } 377 | else if(!haveLeftPage && !haveRightPage){ 378 | _pageMode = JTCalendarPageModeCenter; 379 | } 380 | else if(!haveLeftPage){ 381 | _pageMode = JTCalendarPageModeCenterRight; 382 | } 383 | else{ 384 | _pageMode = JTCalendarPageModeCenterLeft; 385 | } 386 | 387 | if(_manager.settings.pageViewHideWhenPossible){ 388 | _leftView.hidden = !haveLeftPage; 389 | _rightView.hidden = !haveRightPage; 390 | } 391 | else{ 392 | _leftView.hidden = NO; 393 | _rightView.hidden = NO; 394 | } 395 | } 396 | 397 | - (void)repositionViews 398 | { 399 | CGSize size = self.frame.size; 400 | self.contentInset = UIEdgeInsetsZero; 401 | 402 | switch (_pageMode) { 403 | case JTCalendarPageModeFull: 404 | self.contentSize = CGSizeMake(size.width, size.height * 3); 405 | 406 | _leftView.frame = CGRectMake(0, 0, size.width, size.height); 407 | _centerView.frame = CGRectMake(0, size.height, size.width, size.height); 408 | _rightView.frame = CGRectMake(0, size.height * 2, size.width, size.height); 409 | 410 | self.contentOffset = CGPointMake(0, size.height); 411 | break; 412 | case JTCalendarPageModeCenter: 413 | self.contentSize = size; 414 | 415 | _leftView.frame = CGRectMake(0, - size.height, size.width, size.height); 416 | _centerView.frame = CGRectMake(0, 0, size.width, size.height); 417 | _rightView.frame = CGRectMake(0, size.height, size.width, size.height); 418 | 419 | self.contentOffset = CGPointZero; 420 | break; 421 | case JTCalendarPageModeCenterLeft: 422 | self.contentSize = CGSizeMake(size.width, size.height * 2); 423 | 424 | _leftView.frame = CGRectMake(0, 0, size.width, size.height); 425 | _centerView.frame = CGRectMake(0, size.height, size.width, size.height); 426 | _rightView.frame = CGRectMake(0, size.height * 2, size.width, size.height); 427 | 428 | self.contentOffset = CGPointMake(0, size.height); 429 | break; 430 | case JTCalendarPageModeCenterRight: 431 | self.contentSize = CGSizeMake(size.width, size.height * 2); 432 | 433 | _leftView.frame = CGRectMake(0, - size.height, size.width, size.height); 434 | _centerView.frame = CGRectMake(0, 0, size.width, size.height); 435 | _rightView.frame = CGRectMake(0, size.height, size.width, size.height); 436 | 437 | self.contentOffset = CGPointZero; 438 | break; 439 | } 440 | } 441 | 442 | - (void)updateMenuDates 443 | { 444 | [_manager.scrollManager setMenuPreviousDate:_leftView.date 445 | currentDate:_centerView.date 446 | nextDate:_rightView.date]; 447 | } 448 | @end 449 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Jonathan VUKOVICH TRIBOUHARET 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JTCalendar 2 | 3 | [![CI Status](http://img.shields.io/travis/jonathantribouharet/JTCalendar.svg)](https://travis-ci.org/jonathantribouharet/JTCalendar) 4 | ![Version](https://img.shields.io/cocoapods/v/JTCalendar.svg) 5 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 6 | ![License](https://img.shields.io/cocoapods/l/JTCalendar.svg) 7 | ![Platform](https://img.shields.io/cocoapods/p/JTCalendar.svg) 8 | 9 | JTCalendar is an easily customizable calendar control for iOS. 10 | 11 | ## Installation 12 | 13 | With [CocoaPods](http://cocoapods.org), add this line to your Podfile. 14 | 15 | pod 'JTCalendar', '~> 2.0' 16 | 17 | ### Carthage 18 | 19 | To use this project with [Carthage](https://github.com/Carthage/Carthage), add this line to your Cartfile. 20 | 21 | github "jonathantribouharet/JTCalendar" ~> 2.2 22 | 23 | ## Screenshots 24 | 25 | ![Example](./Screens/example.gif "Example View") 26 | ![Example](./Screens/example.png "Example View") 27 | 28 | ### Warning 29 | 30 | The part below the calendar in the 2nd screenshot is not provided. 31 | 32 | ## Features 33 | 34 | - horizontal and vertical calendar 35 | - highly customizable either by subclassing default class provided or by creating your own class implementing a protocol 36 | - support internationalization 37 | - week view mode 38 | - limited range, you can define a start and an end to you calendar 39 | 40 | ## Usage 41 | 42 | ### Basic usage 43 | 44 | You have to create two views in your `UIViewController`: 45 | 46 | - The first view is `JTCalendarMenuView` and it represents the part with the months names. This view is optional. 47 | - The second view is `JTHorizontalCalendarView` or `JTVerticalCalendarView`, it represents the calendar itself. 48 | 49 | Your `UIViewController` have to implement `JTCalendarDelegate`, all methods are optional. 50 | 51 | ```objective-c 52 | #import 53 | 54 | #import 55 | 56 | @interface ViewController : UIViewController 57 | 58 | @property (weak, nonatomic) IBOutlet JTCalendarMenuView *calendarMenuView; 59 | @property (weak, nonatomic) IBOutlet JTHorizontalCalendarView *calendarContentView; 60 | 61 | @property (strong, nonatomic) JTCalendarManager *calendarManager; 62 | 63 | @end 64 | ``` 65 | 66 | `JTCalendarManager` is used to coordinate `calendarMenuView` and `calendarContentView` and provide a default behavior. 67 | 68 | ```objective-c 69 | @implementation ViewController 70 | 71 | - (void)viewDidLoad 72 | { 73 | [super viewDidLoad]; 74 | 75 | _calendarManager = [JTCalendarManager new]; 76 | _calendarManager.delegate = self; 77 | 78 | [_calendarManager setMenuView:_calendarMenuView]; 79 | [_calendarManager setContentView:_calendarContentView]; 80 | [_calendarManager setDate:[NSDate date]]; 81 | } 82 | 83 | @end 84 | 85 | ``` 86 | 87 | The Example project contains some use cases you may check before asking questions. 88 | 89 | ### Advanced usage 90 | 91 | Even if all methods of `JTCalendarManager` are optional you won't get far without implementing at least the two next methods: 92 | - `calendar:prepareDayView:` this method is used to customize the design of the day view for a specific date. This method is called each time a new date is set in a dayView or each time the current page change. You can force the call to this method by calling `[_calendarManager reload];`. 93 | 94 | 95 | ```objective-c 96 | - (void)calendar:(JTCalendarManager *)calendar prepareDayView:(JTCalendarDayView *)dayView 97 | { 98 | dayView.hidden = NO; 99 | 100 | // Test if the dayView is from another month than the page 101 | // Use only in month mode for indicate the day of the previous or next month 102 | if([dayView isFromAnotherMonth]){ 103 | dayView.hidden = YES; 104 | } 105 | // Today 106 | else if([_calendarManager.dateHelper date:[NSDate date] isTheSameDayThan:dayView.date]){ 107 | dayView.circleView.hidden = NO; 108 | dayView.circleView.backgroundColor = [UIColor blueColor]; 109 | dayView.dotView.backgroundColor = [UIColor whiteColor]; 110 | dayView.textLabel.textColor = [UIColor whiteColor]; 111 | } 112 | // Selected date 113 | else if(_dateSelected && [_calendarManager.dateHelper date:_dateSelected isTheSameDayThan:dayView.date]){ 114 | dayView.circleView.hidden = NO; 115 | dayView.circleView.backgroundColor = [UIColor redColor]; 116 | dayView.dotView.backgroundColor = [UIColor whiteColor]; 117 | dayView.textLabel.textColor = [UIColor whiteColor]; 118 | } 119 | // Another day of the current month 120 | else{ 121 | dayView.circleView.hidden = YES; 122 | dayView.dotView.backgroundColor = [UIColor redColor]; 123 | dayView.textLabel.textColor = [UIColor blackColor]; 124 | } 125 | 126 | // Your method to test if a date have an event for example 127 | if([self haveEventForDay:dayView.date]){ 128 | dayView.dotView.hidden = NO; 129 | } 130 | else{ 131 | dayView.dotView.hidden = YES; 132 | } 133 | } 134 | ``` 135 | 136 | - `calendar:didTouchDayView:` this method is used to respond to a touch on a dayView. For example you can indicate to display another month if dayView is from another month. 137 | 138 | ```objective-c 139 | - (void)calendar:(JTCalendarManager *)calendar didTouchDayView:(JTCalendarDayView *)dayView 140 | { 141 | // Use to indicate the selected date 142 | _dateSelected = dayView.date; 143 | 144 | // Animation for the circleView 145 | dayView.circleView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.1, 0.1); 146 | [UIView transitionWithView:dayView 147 | duration:.3 148 | options:0 149 | animations:^{ 150 | dayView.circleView.transform = CGAffineTransformIdentity; 151 | [_calendarManager reload]; 152 | } completion:nil]; 153 | 154 | // Load the previous or next page if touch a day from another month 155 | if(![_calendarManager.dateHelper date:_calendarContentView.date isTheSameMonthThan:dayView.date]){ 156 | if([_calendarContentView.date compare:dayView.date] == NSOrderedAscending){ 157 | [_calendarContentView loadNextPageWithAnimation]; 158 | } 159 | else{ 160 | [_calendarContentView loadPreviousPageWithAnimation]; 161 | } 162 | } 163 | } 164 | ``` 165 | 166 | ### Switch to week view 167 | 168 | If you want see just one week at a time, you have to set the `isWeekMode` to `YES` and reload the calendar. 169 | 170 | ```objective-c 171 | _calendarManager.settings.weekModeEnabled = YES; 172 | [_calendarManager reload]; 173 | ``` 174 | 175 | #### WARNING 176 | 177 | When you change the mode, it doesn't change the height of `calendarContentView`, you have to do it yourself. 178 | See the Example project for more details. 179 | 180 | ### Customize the design 181 | 182 | For customize the design you have to implement some methods depending of what parts you want to custom. Check the [JTCalendarDelegate](JTCalendar/JTCalendarDelegate.h) file and the Example project. 183 | 184 | For example: 185 | 186 | ```objective-c 187 | // This method is independent from the date, it's call only at the creation of the dayView. 188 | // For customize the dayView depending of the date use `prepareDayView` method 189 | - (UIView *)calendarBuildDayView:(JTCalendarManager *)calendar 190 | { 191 | JTCalendarDayView *view = [JTCalendarDayView new]; 192 | view.textLabel.font = [UIFont fontWithName:@"Avenir-Light" size:13]; 193 | view.textLabel.textColor = [UIColor blackColor]; 194 | 195 | return view; 196 | } 197 | ``` 198 | 199 | ### Pagination 200 | 201 | The content views (`JTHorizontalCalendarView` and `JTVerticalCalendarView`) are just subclass of `UIScrollView`. 202 | Each time the current page change, `calendarDidLoadNextPage` or `calendarDidLoadPreviousPage` is called. 203 | The content views provide two method for display the previous or next page with an animation `loadNextPageWithAnimation` and `loadPreviousPageWithAnimation`. 204 | You can limit the range of the calendar by implementing `canDisplayPageWithDate` method. 205 | 206 | ```objective-c 207 | // Used to limit the date for the calendar 208 | - (BOOL)calendar:(JTCalendarManager *)calendar canDisplayPageWithDate:(NSDate *)date 209 | { 210 | return [_calendarManager.dateHelper date:date isEqualOrAfter:_minDate andEqualOrBefore:_maxDate]; 211 | } 212 | ``` 213 | 214 | ### Vertical calendar 215 | 216 | If you use `JTVerticalCalendarView` for having a vertical calendar, you have some settings you have to set. 217 | 218 | ```objective-c 219 | - (void)viewDidLoad 220 | { 221 | [super viewDidLoad]; 222 | 223 | _calendarManager = [JTCalendarManager new]; 224 | _calendarManager.delegate = self; 225 | 226 | _calendarManager.settings.pageViewHaveWeekDaysView = NO; // You don't want WeekDaysView in the contentView 227 | _calendarManager.settings.pageViewNumberOfWeeks = 0; // Automatic number of weeks 228 | 229 | _weekDayView.manager = _calendarManager; // You set the manager for WeekDaysView 230 | [_weekDayView reload]; // You load WeekDaysView manually 231 | 232 | [_calendarManager setMenuView:_calendarMenuView]; 233 | [_calendarManager setContentView:_calendarContentView]; 234 | [_calendarManager setDate:[NSDate date]]; 235 | 236 | _calendarMenuView.scrollView.scrollEnabled = NO; // The scroll is not supported with JTVerticalCalendarView 237 | } 238 | ``` 239 | 240 | ### Internationalization / Localization (change first weekday) 241 | 242 | For changing the locale and the timeZone just do: 243 | 244 | ```objective-c 245 | _calendarManager.dateHelper.calendar.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"CDT"]; 246 | _calendarManager.dateHelper.calendar.locale = [NSLocale localeWithLocaleIdentifier:@"fr_FR"]; 247 | [_calendarManager reload]; 248 | ``` 249 | For changing locale and timeZone in Swift use: 250 | 251 | ```swift 252 | let locale = Locale(identifier: "fr_FR") 253 | let timeZone = TimeZone.init(abbreviation: "CDT") 254 | calendarManager = JTCalendarManager(locale: locale, andTimeZone: timeZone) 255 | ``` 256 | 257 | ### Date comparaison 258 | 259 | Be careful when you compare two different dates, you have to take care of the time zone. 260 | An helper is provided for some basic operations: 261 | 262 | ```objective-c 263 | [_calendarManager.dateHelper date:dateA isTheSameMonthThan:dateB]; 264 | [_calendarManager.dateHelper date:dateA isTheSameWeekThan:dateB]; 265 | [_calendarManager.dateHelper date:dateA isTheSameDayThan:dateB]; 266 | 267 | // Use to limit the calendar range 268 | [_calendarManager.dateHelper date:date isEqualOrAfter:minDate andEqualOrBefore:maxDate]; 269 | 270 | ``` 271 | 272 | ### Optimization 273 | 274 | Every methods in the delegate are called in the main thread, you have to be really careful, in particular in the `prepareDayView` method which is called very often. 275 | 276 | If you have to fetch some data from something slow, I recommend to create a cache and query this cache in `prepareDayView` method. 277 | You have to cache the data from the next pages and update this cache asynchronously (in another thread via `dispatch_async`) when a new page is loaded (via `calendarDidLoadNextPage` and `calendarDidLoadPreviousPage` methods). 278 | 279 | ## Questions 280 | 281 | Before asking any questions be sure to explore the Example project. 282 | Check also [JTCalendarDelegate](JTCalendar/JTCalendarDelegate.h) and [JTCalendarSettings](JTCalendar/JTCalendarSettings.h) files. 283 | 284 | Don't use `NSLog` to print date use a `NSDateFormatter`, `NSLog`doesn't take care of the timezone. 285 | 286 | ```objective-c 287 | NSDateFormatter *dateFormatter = [_calendarManager.dateHelper createDateFormatter]; 288 | dateFormatter.dateFormat = @"yyyy'-'MM'-'dd' 'HH':'mm':'ss"; 289 | NSLog(@"%@", [dateFormatter stringFromDate:yourDate]); 290 | ``` 291 | 292 | ## Requirements 293 | 294 | - iOS 7 or higher 295 | - Automatic Reference Counting (ARC) 296 | 297 | ## Author 298 | 299 | - [Jonathan VUKOVICH TRIBOUHARET](https://github.com/jonathantribouharet) ([@johnvuko](https://twitter.com/johnvuko)) 300 | 301 | ## License 302 | 303 | JTCalendar is released under the MIT license. See the LICENSE file for more info. 304 | -------------------------------------------------------------------------------- /Screens/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnvuko/JTCalendar/238fa1ddfa8f3744bebab6e93aecd3d1f5905875/Screens/example.gif -------------------------------------------------------------------------------- /Screens/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnvuko/JTCalendar/238fa1ddfa8f3744bebab6e93aecd3d1f5905875/Screens/example.png --------------------------------------------------------------------------------