├── .gitignore ├── InfiniteWeekView ├── InfiniteWeekView.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── InfiniteWeekView │ ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Group-1024 1.png │ │ ├── Group-1024.png │ │ ├── Group-128.png │ │ ├── Group-16.png │ │ ├── Group-256 1.png │ │ ├── Group-256.png │ │ ├── Group-32 1.png │ │ ├── Group-32.png │ │ ├── Group-512 1.png │ │ ├── Group-512.png │ │ └── Group-64.png │ ├── Colors │ │ ├── Contents.json │ │ ├── Element.colorset │ │ │ └── Contents.json │ │ └── Section.colorset │ │ │ └── Contents.json │ └── Contents.json │ ├── ContentView.swift │ ├── InfiniteWeekView.entitlements │ ├── InfiniteWeekViewApp.swift │ ├── Models │ ├── Task.swift │ ├── Week.swift │ └── WeekStore.swift │ ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json │ ├── Utils │ ├── Enums │ │ └── TimeDirection.swift │ ├── Extensions │ │ ├── Color+Extension.swift │ │ ├── Date+Extension.swift │ │ └── View+Extension.swift │ ├── MockData │ │ └── MockTasks.swift │ ├── Shapes │ │ └── CornerRadiusShape.swift │ └── ViewModifier │ │ └── CornerRadiusStyle.swift │ ├── ViewModels │ └── TaskViewModel.swift │ └── Views │ ├── Day │ ├── DayView.swift │ └── DaysTabView.swift │ ├── InfiniteWeekView.swift │ ├── Task │ ├── NewTaskForm.swift │ ├── TaskCell.swift │ └── TaskList.swift │ └── Week │ ├── WeekHeaderView.swift │ ├── WeekView.swift │ └── WeeksTabView.swift └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Build generated 2 | build/ 3 | DerivedData/ 4 | 5 | ## Various settings 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata/ 15 | 16 | ## Other 17 | *.moved-aside 18 | *.xccheckout 19 | *.xcscmblueprint 20 | 21 | ## Obj-C/Swift specific 22 | *.hmap 23 | *.ipa 24 | *.dSYM.zip 25 | *.dSYM 26 | 27 | ## Playgrounds 28 | timeline.xctimeline 29 | playground.xcworkspace 30 | 31 | # Swift Package Manager 32 | # 33 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 34 | # Packages/ 35 | # Package.pins 36 | .build/ 37 | 38 | # Fastlane 39 | **/fastlane/README.md 40 | **/fastlane/report.xml 41 | **/fastlane/Preview.html 42 | **/fastlane/test_output 43 | 44 | # Jazzy 45 | **/docs 46 | 47 | # Temporary and files 48 | *~ 49 | *.bck 50 | *.tmp 51 | *.swp 52 | 53 | # OS generated files 54 | .DS_Store* 55 | ehthumbs.db 56 | Thumbs.db -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 9A22D4D42A0FE73A005113A9 /* InfiniteWeekViewApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D4D32A0FE73A005113A9 /* InfiniteWeekViewApp.swift */; }; 11 | 9A22D4D62A0FE73A005113A9 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D4D52A0FE73A005113A9 /* ContentView.swift */; }; 12 | 9A22D4D82A0FE73B005113A9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9A22D4D72A0FE73B005113A9 /* Assets.xcassets */; }; 13 | 9A22D4DC2A0FE73B005113A9 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9A22D4DB2A0FE73B005113A9 /* Preview Assets.xcassets */; }; 14 | 9A22D4FD2A0FEFAB005113A9 /* InfiniteWeekView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D4FC2A0FEFAB005113A9 /* InfiniteWeekView.swift */; }; 15 | 9A22D4FF2A0FEFD9005113A9 /* WeekStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D4FE2A0FEFD9005113A9 /* WeekStore.swift */; }; 16 | 9A22D5012A0FEFF4005113A9 /* Week.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D5002A0FEFF4005113A9 /* Week.swift */; }; 17 | 9A22D5032A0FF00E005113A9 /* Task.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D5022A0FF00E005113A9 /* Task.swift */; }; 18 | 9A22D50A2A0FF064005113A9 /* CornerRadiusStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D5092A0FF064005113A9 /* CornerRadiusStyle.swift */; }; 19 | 9A22D50C2A0FF086005113A9 /* CornerRadiusShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D50B2A0FF086005113A9 /* CornerRadiusShape.swift */; }; 20 | 9A22D50E2A0FF0A1005113A9 /* MockTasks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D50D2A0FF0A1005113A9 /* MockTasks.swift */; }; 21 | 9A22D5102A0FF0C3005113A9 /* TimeDirection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D50F2A0FF0C3005113A9 /* TimeDirection.swift */; }; 22 | 9A22D5122A0FF0E9005113A9 /* Color+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D5112A0FF0E9005113A9 /* Color+Extension.swift */; }; 23 | 9A22D5142A0FF10E005113A9 /* Date+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D5132A0FF10E005113A9 /* Date+Extension.swift */; }; 24 | 9A22D5162A0FF132005113A9 /* View+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D5152A0FF132005113A9 /* View+Extension.swift */; }; 25 | 9A22D5182A0FF152005113A9 /* TaskViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D5172A0FF152005113A9 /* TaskViewModel.swift */; }; 26 | 9A22D51D2A0FF19E005113A9 /* WeekHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D51C2A0FF19E005113A9 /* WeekHeaderView.swift */; }; 27 | 9A22D51F2A0FF1C8005113A9 /* WeeksTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D51E2A0FF1C8005113A9 /* WeeksTabView.swift */; }; 28 | 9A22D5212A0FF1D7005113A9 /* WeekView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D5202A0FF1D7005113A9 /* WeekView.swift */; }; 29 | 9A22D5232A0FF1FA005113A9 /* DaysTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D5222A0FF1FA005113A9 /* DaysTabView.swift */; }; 30 | 9A22D5252A0FF21B005113A9 /* DayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D5242A0FF21B005113A9 /* DayView.swift */; }; 31 | 9A22D5272A0FF234005113A9 /* TaskCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D5262A0FF234005113A9 /* TaskCell.swift */; }; 32 | 9A22D5292A0FF250005113A9 /* TaskList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D5282A0FF250005113A9 /* TaskList.swift */; }; 33 | 9A22D52B2A0FF274005113A9 /* NewTaskForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A22D52A2A0FF274005113A9 /* NewTaskForm.swift */; }; 34 | /* End PBXBuildFile section */ 35 | 36 | /* Begin PBXFileReference section */ 37 | 9A22D4D02A0FE73A005113A9 /* InfiniteWeekView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = InfiniteWeekView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | 9A22D4D32A0FE73A005113A9 /* InfiniteWeekViewApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfiniteWeekViewApp.swift; sourceTree = ""; }; 39 | 9A22D4D52A0FE73A005113A9 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 40 | 9A22D4D72A0FE73B005113A9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 41 | 9A22D4D92A0FE73B005113A9 /* InfiniteWeekView.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = InfiniteWeekView.entitlements; sourceTree = ""; }; 42 | 9A22D4DB2A0FE73B005113A9 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 43 | 9A22D4FC2A0FEFAB005113A9 /* InfiniteWeekView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfiniteWeekView.swift; sourceTree = ""; }; 44 | 9A22D4FE2A0FEFD9005113A9 /* WeekStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeekStore.swift; sourceTree = ""; }; 45 | 9A22D5002A0FEFF4005113A9 /* Week.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Week.swift; sourceTree = ""; }; 46 | 9A22D5022A0FF00E005113A9 /* Task.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Task.swift; sourceTree = ""; }; 47 | 9A22D5092A0FF064005113A9 /* CornerRadiusStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerRadiusStyle.swift; sourceTree = ""; }; 48 | 9A22D50B2A0FF086005113A9 /* CornerRadiusShape.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerRadiusShape.swift; sourceTree = ""; }; 49 | 9A22D50D2A0FF0A1005113A9 /* MockTasks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTasks.swift; sourceTree = ""; }; 50 | 9A22D50F2A0FF0C3005113A9 /* TimeDirection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeDirection.swift; sourceTree = ""; }; 51 | 9A22D5112A0FF0E9005113A9 /* Color+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Extension.swift"; sourceTree = ""; }; 52 | 9A22D5132A0FF10E005113A9 /* Date+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Extension.swift"; sourceTree = ""; }; 53 | 9A22D5152A0FF132005113A9 /* View+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extension.swift"; sourceTree = ""; }; 54 | 9A22D5172A0FF152005113A9 /* TaskViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskViewModel.swift; sourceTree = ""; }; 55 | 9A22D51C2A0FF19E005113A9 /* WeekHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeekHeaderView.swift; sourceTree = ""; }; 56 | 9A22D51E2A0FF1C8005113A9 /* WeeksTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeeksTabView.swift; sourceTree = ""; }; 57 | 9A22D5202A0FF1D7005113A9 /* WeekView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeekView.swift; sourceTree = ""; }; 58 | 9A22D5222A0FF1FA005113A9 /* DaysTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DaysTabView.swift; sourceTree = ""; }; 59 | 9A22D5242A0FF21B005113A9 /* DayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DayView.swift; sourceTree = ""; }; 60 | 9A22D5262A0FF234005113A9 /* TaskCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskCell.swift; sourceTree = ""; }; 61 | 9A22D5282A0FF250005113A9 /* TaskList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskList.swift; sourceTree = ""; }; 62 | 9A22D52A2A0FF274005113A9 /* NewTaskForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTaskForm.swift; sourceTree = ""; }; 63 | /* End PBXFileReference section */ 64 | 65 | /* Begin PBXFrameworksBuildPhase section */ 66 | 9A22D4CD2A0FE73A005113A9 /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | ); 71 | runOnlyForDeploymentPostprocessing = 0; 72 | }; 73 | /* End PBXFrameworksBuildPhase section */ 74 | 75 | /* Begin PBXGroup section */ 76 | 9A22D4C72A0FE73A005113A9 = { 77 | isa = PBXGroup; 78 | children = ( 79 | 9A22D4D22A0FE73A005113A9 /* InfiniteWeekView */, 80 | 9A22D4D12A0FE73A005113A9 /* Products */, 81 | ); 82 | sourceTree = ""; 83 | }; 84 | 9A22D4D12A0FE73A005113A9 /* Products */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 9A22D4D02A0FE73A005113A9 /* InfiniteWeekView.app */, 88 | ); 89 | name = Products; 90 | sourceTree = ""; 91 | }; 92 | 9A22D4D22A0FE73A005113A9 /* InfiniteWeekView */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 9A22D4D32A0FE73A005113A9 /* InfiniteWeekViewApp.swift */, 96 | 9A22D4D52A0FE73A005113A9 /* ContentView.swift */, 97 | 9A22D4F82A0FEF72005113A9 /* Views */, 98 | 9A22D4FB2A0FEF88005113A9 /* ViewModels */, 99 | 9A22D4F92A0FEF7B005113A9 /* Models */, 100 | 9A22D4FA2A0FEF82005113A9 /* Utils */, 101 | 9A22D4D72A0FE73B005113A9 /* Assets.xcassets */, 102 | 9A22D4D92A0FE73B005113A9 /* InfiniteWeekView.entitlements */, 103 | 9A22D4DA2A0FE73B005113A9 /* Preview Content */, 104 | ); 105 | path = InfiniteWeekView; 106 | sourceTree = ""; 107 | }; 108 | 9A22D4DA2A0FE73B005113A9 /* Preview Content */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 9A22D4DB2A0FE73B005113A9 /* Preview Assets.xcassets */, 112 | ); 113 | path = "Preview Content"; 114 | sourceTree = ""; 115 | }; 116 | 9A22D4F82A0FEF72005113A9 /* Views */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | 9A22D4FC2A0FEFAB005113A9 /* InfiniteWeekView.swift */, 120 | 9A22D5192A0FF16F005113A9 /* Week */, 121 | 9A22D51A2A0FF175005113A9 /* Day */, 122 | 9A22D51B2A0FF17C005113A9 /* Task */, 123 | ); 124 | path = Views; 125 | sourceTree = ""; 126 | }; 127 | 9A22D4F92A0FEF7B005113A9 /* Models */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | 9A22D4FE2A0FEFD9005113A9 /* WeekStore.swift */, 131 | 9A22D5002A0FEFF4005113A9 /* Week.swift */, 132 | 9A22D5022A0FF00E005113A9 /* Task.swift */, 133 | ); 134 | path = Models; 135 | sourceTree = ""; 136 | }; 137 | 9A22D4FA2A0FEF82005113A9 /* Utils */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | 9A22D5082A0FF03A005113A9 /* ViewModifier */, 141 | 9A22D5072A0FF034005113A9 /* Shapes */, 142 | 9A22D5062A0FF02D005113A9 /* MockData */, 143 | 9A22D5052A0FF025005113A9 /* Extensions */, 144 | 9A22D5042A0FF01F005113A9 /* Enums */, 145 | ); 146 | path = Utils; 147 | sourceTree = ""; 148 | }; 149 | 9A22D4FB2A0FEF88005113A9 /* ViewModels */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | 9A22D5172A0FF152005113A9 /* TaskViewModel.swift */, 153 | ); 154 | path = ViewModels; 155 | sourceTree = ""; 156 | }; 157 | 9A22D5042A0FF01F005113A9 /* Enums */ = { 158 | isa = PBXGroup; 159 | children = ( 160 | 9A22D50F2A0FF0C3005113A9 /* TimeDirection.swift */, 161 | ); 162 | path = Enums; 163 | sourceTree = ""; 164 | }; 165 | 9A22D5052A0FF025005113A9 /* Extensions */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | 9A22D5112A0FF0E9005113A9 /* Color+Extension.swift */, 169 | 9A22D5132A0FF10E005113A9 /* Date+Extension.swift */, 170 | 9A22D5152A0FF132005113A9 /* View+Extension.swift */, 171 | ); 172 | path = Extensions; 173 | sourceTree = ""; 174 | }; 175 | 9A22D5062A0FF02D005113A9 /* MockData */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | 9A22D50D2A0FF0A1005113A9 /* MockTasks.swift */, 179 | ); 180 | path = MockData; 181 | sourceTree = ""; 182 | }; 183 | 9A22D5072A0FF034005113A9 /* Shapes */ = { 184 | isa = PBXGroup; 185 | children = ( 186 | 9A22D50B2A0FF086005113A9 /* CornerRadiusShape.swift */, 187 | ); 188 | path = Shapes; 189 | sourceTree = ""; 190 | }; 191 | 9A22D5082A0FF03A005113A9 /* ViewModifier */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | 9A22D5092A0FF064005113A9 /* CornerRadiusStyle.swift */, 195 | ); 196 | path = ViewModifier; 197 | sourceTree = ""; 198 | }; 199 | 9A22D5192A0FF16F005113A9 /* Week */ = { 200 | isa = PBXGroup; 201 | children = ( 202 | 9A22D51C2A0FF19E005113A9 /* WeekHeaderView.swift */, 203 | 9A22D51E2A0FF1C8005113A9 /* WeeksTabView.swift */, 204 | 9A22D5202A0FF1D7005113A9 /* WeekView.swift */, 205 | ); 206 | path = Week; 207 | sourceTree = ""; 208 | }; 209 | 9A22D51A2A0FF175005113A9 /* Day */ = { 210 | isa = PBXGroup; 211 | children = ( 212 | 9A22D5222A0FF1FA005113A9 /* DaysTabView.swift */, 213 | 9A22D5242A0FF21B005113A9 /* DayView.swift */, 214 | ); 215 | path = Day; 216 | sourceTree = ""; 217 | }; 218 | 9A22D51B2A0FF17C005113A9 /* Task */ = { 219 | isa = PBXGroup; 220 | children = ( 221 | 9A22D5262A0FF234005113A9 /* TaskCell.swift */, 222 | 9A22D5282A0FF250005113A9 /* TaskList.swift */, 223 | 9A22D52A2A0FF274005113A9 /* NewTaskForm.swift */, 224 | ); 225 | path = Task; 226 | sourceTree = ""; 227 | }; 228 | /* End PBXGroup section */ 229 | 230 | /* Begin PBXNativeTarget section */ 231 | 9A22D4CF2A0FE73A005113A9 /* InfiniteWeekView */ = { 232 | isa = PBXNativeTarget; 233 | buildConfigurationList = 9A22D4DF2A0FE73B005113A9 /* Build configuration list for PBXNativeTarget "InfiniteWeekView" */; 234 | buildPhases = ( 235 | 9A22D4CC2A0FE73A005113A9 /* Sources */, 236 | 9A22D4CD2A0FE73A005113A9 /* Frameworks */, 237 | 9A22D4CE2A0FE73A005113A9 /* Resources */, 238 | ); 239 | buildRules = ( 240 | ); 241 | dependencies = ( 242 | ); 243 | name = InfiniteWeekView; 244 | productName = InfiniteWeekView; 245 | productReference = 9A22D4D02A0FE73A005113A9 /* InfiniteWeekView.app */; 246 | productType = "com.apple.product-type.application"; 247 | }; 248 | /* End PBXNativeTarget section */ 249 | 250 | /* Begin PBXProject section */ 251 | 9A22D4C82A0FE73A005113A9 /* Project object */ = { 252 | isa = PBXProject; 253 | attributes = { 254 | BuildIndependentTargetsInParallel = 1; 255 | LastSwiftUpdateCheck = 1430; 256 | LastUpgradeCheck = 1430; 257 | TargetAttributes = { 258 | 9A22D4CF2A0FE73A005113A9 = { 259 | CreatedOnToolsVersion = 14.3; 260 | }; 261 | }; 262 | }; 263 | buildConfigurationList = 9A22D4CB2A0FE73A005113A9 /* Build configuration list for PBXProject "InfiniteWeekView" */; 264 | compatibilityVersion = "Xcode 14.0"; 265 | developmentRegion = en; 266 | hasScannedForEncodings = 0; 267 | knownRegions = ( 268 | en, 269 | Base, 270 | ); 271 | mainGroup = 9A22D4C72A0FE73A005113A9; 272 | productRefGroup = 9A22D4D12A0FE73A005113A9 /* Products */; 273 | projectDirPath = ""; 274 | projectRoot = ""; 275 | targets = ( 276 | 9A22D4CF2A0FE73A005113A9 /* InfiniteWeekView */, 277 | ); 278 | }; 279 | /* End PBXProject section */ 280 | 281 | /* Begin PBXResourcesBuildPhase section */ 282 | 9A22D4CE2A0FE73A005113A9 /* Resources */ = { 283 | isa = PBXResourcesBuildPhase; 284 | buildActionMask = 2147483647; 285 | files = ( 286 | 9A22D4DC2A0FE73B005113A9 /* Preview Assets.xcassets in Resources */, 287 | 9A22D4D82A0FE73B005113A9 /* Assets.xcassets in Resources */, 288 | ); 289 | runOnlyForDeploymentPostprocessing = 0; 290 | }; 291 | /* End PBXResourcesBuildPhase section */ 292 | 293 | /* Begin PBXSourcesBuildPhase section */ 294 | 9A22D4CC2A0FE73A005113A9 /* Sources */ = { 295 | isa = PBXSourcesBuildPhase; 296 | buildActionMask = 2147483647; 297 | files = ( 298 | 9A22D5292A0FF250005113A9 /* TaskList.swift in Sources */, 299 | 9A22D4FD2A0FEFAB005113A9 /* InfiniteWeekView.swift in Sources */, 300 | 9A22D5182A0FF152005113A9 /* TaskViewModel.swift in Sources */, 301 | 9A22D4D62A0FE73A005113A9 /* ContentView.swift in Sources */, 302 | 9A22D5102A0FF0C3005113A9 /* TimeDirection.swift in Sources */, 303 | 9A22D5272A0FF234005113A9 /* TaskCell.swift in Sources */, 304 | 9A22D5012A0FEFF4005113A9 /* Week.swift in Sources */, 305 | 9A22D50E2A0FF0A1005113A9 /* MockTasks.swift in Sources */, 306 | 9A22D5212A0FF1D7005113A9 /* WeekView.swift in Sources */, 307 | 9A22D5142A0FF10E005113A9 /* Date+Extension.swift in Sources */, 308 | 9A22D4D42A0FE73A005113A9 /* InfiniteWeekViewApp.swift in Sources */, 309 | 9A22D52B2A0FF274005113A9 /* NewTaskForm.swift in Sources */, 310 | 9A22D50C2A0FF086005113A9 /* CornerRadiusShape.swift in Sources */, 311 | 9A22D50A2A0FF064005113A9 /* CornerRadiusStyle.swift in Sources */, 312 | 9A22D5032A0FF00E005113A9 /* Task.swift in Sources */, 313 | 9A22D51D2A0FF19E005113A9 /* WeekHeaderView.swift in Sources */, 314 | 9A22D5232A0FF1FA005113A9 /* DaysTabView.swift in Sources */, 315 | 9A22D5162A0FF132005113A9 /* View+Extension.swift in Sources */, 316 | 9A22D5122A0FF0E9005113A9 /* Color+Extension.swift in Sources */, 317 | 9A22D51F2A0FF1C8005113A9 /* WeeksTabView.swift in Sources */, 318 | 9A22D4FF2A0FEFD9005113A9 /* WeekStore.swift in Sources */, 319 | 9A22D5252A0FF21B005113A9 /* DayView.swift in Sources */, 320 | ); 321 | runOnlyForDeploymentPostprocessing = 0; 322 | }; 323 | /* End PBXSourcesBuildPhase section */ 324 | 325 | /* Begin XCBuildConfiguration section */ 326 | 9A22D4DD2A0FE73B005113A9 /* Debug */ = { 327 | isa = XCBuildConfiguration; 328 | buildSettings = { 329 | ALWAYS_SEARCH_USER_PATHS = NO; 330 | CLANG_ANALYZER_NONNULL = YES; 331 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 332 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 333 | CLANG_ENABLE_MODULES = YES; 334 | CLANG_ENABLE_OBJC_ARC = YES; 335 | CLANG_ENABLE_OBJC_WEAK = YES; 336 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 337 | CLANG_WARN_BOOL_CONVERSION = YES; 338 | CLANG_WARN_COMMA = YES; 339 | CLANG_WARN_CONSTANT_CONVERSION = YES; 340 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 341 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 342 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 343 | CLANG_WARN_EMPTY_BODY = YES; 344 | CLANG_WARN_ENUM_CONVERSION = YES; 345 | CLANG_WARN_INFINITE_RECURSION = YES; 346 | CLANG_WARN_INT_CONVERSION = YES; 347 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 348 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 349 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 350 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 351 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 352 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 353 | CLANG_WARN_STRICT_PROTOTYPES = YES; 354 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 355 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 356 | CLANG_WARN_UNREACHABLE_CODE = YES; 357 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 358 | COPY_PHASE_STRIP = NO; 359 | DEBUG_INFORMATION_FORMAT = dwarf; 360 | ENABLE_STRICT_OBJC_MSGSEND = YES; 361 | ENABLE_TESTABILITY = YES; 362 | GCC_C_LANGUAGE_STANDARD = gnu11; 363 | GCC_DYNAMIC_NO_PIC = NO; 364 | GCC_NO_COMMON_BLOCKS = YES; 365 | GCC_OPTIMIZATION_LEVEL = 0; 366 | GCC_PREPROCESSOR_DEFINITIONS = ( 367 | "DEBUG=1", 368 | "$(inherited)", 369 | ); 370 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 371 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 372 | GCC_WARN_UNDECLARED_SELECTOR = YES; 373 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 374 | GCC_WARN_UNUSED_FUNCTION = YES; 375 | GCC_WARN_UNUSED_VARIABLE = YES; 376 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 377 | MTL_FAST_MATH = YES; 378 | ONLY_ACTIVE_ARCH = YES; 379 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 380 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 381 | }; 382 | name = Debug; 383 | }; 384 | 9A22D4DE2A0FE73B005113A9 /* Release */ = { 385 | isa = XCBuildConfiguration; 386 | buildSettings = { 387 | ALWAYS_SEARCH_USER_PATHS = NO; 388 | CLANG_ANALYZER_NONNULL = YES; 389 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 390 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 391 | CLANG_ENABLE_MODULES = YES; 392 | CLANG_ENABLE_OBJC_ARC = YES; 393 | CLANG_ENABLE_OBJC_WEAK = YES; 394 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 395 | CLANG_WARN_BOOL_CONVERSION = YES; 396 | CLANG_WARN_COMMA = YES; 397 | CLANG_WARN_CONSTANT_CONVERSION = YES; 398 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 399 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 400 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 401 | CLANG_WARN_EMPTY_BODY = YES; 402 | CLANG_WARN_ENUM_CONVERSION = YES; 403 | CLANG_WARN_INFINITE_RECURSION = YES; 404 | CLANG_WARN_INT_CONVERSION = YES; 405 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 406 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 407 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 408 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 409 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 410 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 411 | CLANG_WARN_STRICT_PROTOTYPES = YES; 412 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 413 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 414 | CLANG_WARN_UNREACHABLE_CODE = YES; 415 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 416 | COPY_PHASE_STRIP = NO; 417 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 418 | ENABLE_NS_ASSERTIONS = NO; 419 | ENABLE_STRICT_OBJC_MSGSEND = YES; 420 | GCC_C_LANGUAGE_STANDARD = gnu11; 421 | GCC_NO_COMMON_BLOCKS = YES; 422 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 423 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 424 | GCC_WARN_UNDECLARED_SELECTOR = YES; 425 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 426 | GCC_WARN_UNUSED_FUNCTION = YES; 427 | GCC_WARN_UNUSED_VARIABLE = YES; 428 | MTL_ENABLE_DEBUG_INFO = NO; 429 | MTL_FAST_MATH = YES; 430 | SWIFT_COMPILATION_MODE = wholemodule; 431 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 432 | }; 433 | name = Release; 434 | }; 435 | 9A22D4E02A0FE73B005113A9 /* Debug */ = { 436 | isa = XCBuildConfiguration; 437 | buildSettings = { 438 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 439 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 440 | CODE_SIGN_ENTITLEMENTS = InfiniteWeekView/InfiniteWeekView.entitlements; 441 | CODE_SIGN_STYLE = Automatic; 442 | CURRENT_PROJECT_VERSION = 1; 443 | DEVELOPMENT_ASSET_PATHS = "\"InfiniteWeekView/Preview Content\""; 444 | DEVELOPMENT_TEAM = LYWDH9JL47; 445 | ENABLE_HARDENED_RUNTIME = YES; 446 | ENABLE_PREVIEWS = YES; 447 | GENERATE_INFOPLIST_FILE = YES; 448 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; 449 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; 450 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; 451 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES; 452 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES; 453 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES; 454 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault; 455 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; 456 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 457 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 458 | IPHONEOS_DEPLOYMENT_TARGET = 16.4; 459 | LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; 460 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; 461 | MACOSX_DEPLOYMENT_TARGET = 13.0; 462 | MARKETING_VERSION = 1.0; 463 | PRODUCT_BUNDLE_IDENTIFIER = com.carlphilippknoblauch.InfiniteWeekView; 464 | PRODUCT_NAME = "$(TARGET_NAME)"; 465 | SDKROOT = auto; 466 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; 467 | SWIFT_EMIT_LOC_STRINGS = YES; 468 | SWIFT_VERSION = 5.0; 469 | TARGETED_DEVICE_FAMILY = "1,2"; 470 | }; 471 | name = Debug; 472 | }; 473 | 9A22D4E12A0FE73B005113A9 /* Release */ = { 474 | isa = XCBuildConfiguration; 475 | buildSettings = { 476 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 477 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 478 | CODE_SIGN_ENTITLEMENTS = InfiniteWeekView/InfiniteWeekView.entitlements; 479 | CODE_SIGN_STYLE = Automatic; 480 | CURRENT_PROJECT_VERSION = 1; 481 | DEVELOPMENT_ASSET_PATHS = "\"InfiniteWeekView/Preview Content\""; 482 | DEVELOPMENT_TEAM = LYWDH9JL47; 483 | ENABLE_HARDENED_RUNTIME = YES; 484 | ENABLE_PREVIEWS = YES; 485 | GENERATE_INFOPLIST_FILE = YES; 486 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; 487 | "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; 488 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; 489 | "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES; 490 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES; 491 | "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES; 492 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault; 493 | "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; 494 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 495 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 496 | IPHONEOS_DEPLOYMENT_TARGET = 16.4; 497 | LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; 498 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; 499 | MACOSX_DEPLOYMENT_TARGET = 13.0; 500 | MARKETING_VERSION = 1.0; 501 | PRODUCT_BUNDLE_IDENTIFIER = com.carlphilippknoblauch.InfiniteWeekView; 502 | PRODUCT_NAME = "$(TARGET_NAME)"; 503 | SDKROOT = auto; 504 | SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; 505 | SWIFT_EMIT_LOC_STRINGS = YES; 506 | SWIFT_VERSION = 5.0; 507 | TARGETED_DEVICE_FAMILY = "1,2"; 508 | }; 509 | name = Release; 510 | }; 511 | /* End XCBuildConfiguration section */ 512 | 513 | /* Begin XCConfigurationList section */ 514 | 9A22D4CB2A0FE73A005113A9 /* Build configuration list for PBXProject "InfiniteWeekView" */ = { 515 | isa = XCConfigurationList; 516 | buildConfigurations = ( 517 | 9A22D4DD2A0FE73B005113A9 /* Debug */, 518 | 9A22D4DE2A0FE73B005113A9 /* Release */, 519 | ); 520 | defaultConfigurationIsVisible = 0; 521 | defaultConfigurationName = Release; 522 | }; 523 | 9A22D4DF2A0FE73B005113A9 /* Build configuration list for PBXNativeTarget "InfiniteWeekView" */ = { 524 | isa = XCConfigurationList; 525 | buildConfigurations = ( 526 | 9A22D4E02A0FE73B005113A9 /* Debug */, 527 | 9A22D4E12A0FE73B005113A9 /* Release */, 528 | ); 529 | defaultConfigurationIsVisible = 0; 530 | defaultConfigurationName = Release; 531 | }; 532 | /* End XCConfigurationList section */ 533 | }; 534 | rootObject = 9A22D4C82A0FE73A005113A9 /* Project object */; 535 | } 536 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Group-1024.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | }, 9 | { 10 | "filename" : "Group-16.png", 11 | "idiom" : "mac", 12 | "scale" : "1x", 13 | "size" : "16x16" 14 | }, 15 | { 16 | "filename" : "Group-32.png", 17 | "idiom" : "mac", 18 | "scale" : "2x", 19 | "size" : "16x16" 20 | }, 21 | { 22 | "filename" : "Group-32 1.png", 23 | "idiom" : "mac", 24 | "scale" : "1x", 25 | "size" : "32x32" 26 | }, 27 | { 28 | "filename" : "Group-64.png", 29 | "idiom" : "mac", 30 | "scale" : "2x", 31 | "size" : "32x32" 32 | }, 33 | { 34 | "filename" : "Group-128.png", 35 | "idiom" : "mac", 36 | "scale" : "1x", 37 | "size" : "128x128" 38 | }, 39 | { 40 | "filename" : "Group-256.png", 41 | "idiom" : "mac", 42 | "scale" : "2x", 43 | "size" : "128x128" 44 | }, 45 | { 46 | "filename" : "Group-256 1.png", 47 | "idiom" : "mac", 48 | "scale" : "1x", 49 | "size" : "256x256" 50 | }, 51 | { 52 | "filename" : "Group-512.png", 53 | "idiom" : "mac", 54 | "scale" : "2x", 55 | "size" : "256x256" 56 | }, 57 | { 58 | "filename" : "Group-512 1.png", 59 | "idiom" : "mac", 60 | "scale" : "1x", 61 | "size" : "512x512" 62 | }, 63 | { 64 | "filename" : "Group-1024 1.png", 65 | "idiom" : "mac", 66 | "scale" : "2x", 67 | "size" : "512x512" 68 | } 69 | ], 70 | "info" : { 71 | "author" : "xcode", 72 | "version" : 1 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-1024 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philippkno/InfiniteWeekView/4425e0ab0a6355dd37e30e599b7a3100753618a3/InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-1024 1.png -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philippkno/InfiniteWeekView/4425e0ab0a6355dd37e30e599b7a3100753618a3/InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-1024.png -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philippkno/InfiniteWeekView/4425e0ab0a6355dd37e30e599b7a3100753618a3/InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-128.png -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philippkno/InfiniteWeekView/4425e0ab0a6355dd37e30e599b7a3100753618a3/InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-16.png -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-256 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philippkno/InfiniteWeekView/4425e0ab0a6355dd37e30e599b7a3100753618a3/InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-256 1.png -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philippkno/InfiniteWeekView/4425e0ab0a6355dd37e30e599b7a3100753618a3/InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-256.png -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-32 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philippkno/InfiniteWeekView/4425e0ab0a6355dd37e30e599b7a3100753618a3/InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-32 1.png -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philippkno/InfiniteWeekView/4425e0ab0a6355dd37e30e599b7a3100753618a3/InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-32.png -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-512 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philippkno/InfiniteWeekView/4425e0ab0a6355dd37e30e599b7a3100753618a3/InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-512 1.png -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philippkno/InfiniteWeekView/4425e0ab0a6355dd37e30e599b7a3100753618a3/InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-512.png -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/philippkno/InfiniteWeekView/4425e0ab0a6355dd37e30e599b7a3100753618a3/InfiniteWeekView/InfiniteWeekView/Assets.xcassets/AppIcon.appiconset/Group-64.png -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Assets.xcassets/Colors/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Assets.xcassets/Colors/Element.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "0.200", 8 | "blue" : "0.333", 9 | "green" : "0.333", 10 | "red" : "0.333" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0.333", 27 | "green" : "0.333", 28 | "red" : "0.333" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Assets.xcassets/Colors/Section.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "0.100", 8 | "blue" : "0x19", 9 | "green" : "0x19", 10 | "red" : "0x1A" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x19", 27 | "green" : "0x19", 28 | "red" : "0x1A" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ContentView: View { 11 | @StateObject var weekStore: WeekStore = WeekStore() 12 | 13 | var body: some View { 14 | InfiniteWeekView() 15 | .environmentObject(weekStore) 16 | 17 | } 18 | } 19 | 20 | struct ContentView_Previews: PreviewProvider { 21 | static var previews: some View { 22 | ContentView() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/InfiniteWeekView.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/InfiniteWeekViewApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InfiniteWeekViewApp.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct InfiniteWeekViewApp: App { 12 | var body: some Scene { 13 | WindowGroup { 14 | ContentView() 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Models/Task.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Task.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import Foundation 9 | 10 | struct Task: Identifiable { 11 | let id: UUID = .init() 12 | let iconName: String 13 | let date: Date 14 | let description: String 15 | var isCompleted: Bool 16 | } 17 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Models/Week.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Week.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import Foundation 9 | 10 | struct Week { 11 | let index: Int 12 | let dates: [Date] 13 | var referenceDate: Date 14 | } 15 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Models/WeekStore.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WeekStore.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import Foundation 9 | 10 | class WeekStore: ObservableObject { 11 | @Published var weeks: [Week] = [] 12 | @Published var selectedDate: Date { 13 | didSet { 14 | calcWeeks(with: selectedDate) 15 | } 16 | } 17 | 18 | init(with date: Date = Date()) { 19 | self.selectedDate = Calendar.current.startOfDay(for: date) 20 | calcWeeks(with: selectedDate) 21 | } 22 | 23 | private func calcWeeks(with date: Date) { 24 | weeks = [ 25 | week(for: Calendar.current.date(byAdding: .day, value: -7, to: date)!, with: -1), 26 | week(for: date, with: 0), 27 | week(for: Calendar.current.date(byAdding: .day, value: 7, to: date)!, with: 1) 28 | ] 29 | } 30 | 31 | private func week(for date: Date, with index: Int) -> Week { 32 | var result: [Date] = .init() 33 | 34 | guard let startOfWeek = Calendar.current.date(from: Calendar.current.dateComponents([.yearForWeekOfYear, .weekOfYear], from: date)) else { return .init(index: index, dates: [], referenceDate: date) } 35 | 36 | (0...6).forEach { day in 37 | if let weekday = Calendar.current.date(byAdding: .day, value: day, to: startOfWeek) { 38 | result.append(weekday) 39 | } 40 | } 41 | 42 | return .init(index: index, dates: result, referenceDate: date) 43 | } 44 | 45 | func selectToday() { 46 | select(date: Date()) 47 | } 48 | 49 | func select(date: Date) { 50 | selectedDate = Calendar.current.startOfDay(for: date) 51 | } 52 | 53 | func update(to direction: TimeDirection) { 54 | switch direction { 55 | case .future: 56 | selectedDate = Calendar.current.date(byAdding: .day, value: 7, to: selectedDate)! 57 | 58 | case .past: 59 | selectedDate = Calendar.current.date(byAdding: .day, value: -7, to: selectedDate)! 60 | 61 | case .unknown: 62 | selectedDate = selectedDate 63 | } 64 | 65 | calcWeeks(with: selectedDate) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Utils/Enums/TimeDirection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TimeDirection.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import Foundation 9 | 10 | enum TimeDirection { 11 | case future 12 | case past 13 | case unknown 14 | } 15 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Utils/Extensions/Color+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Color+Extension.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | extension Color { 11 | static let section = Color("Section") 12 | static let element = Color("Element") 13 | } 14 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Utils/Extensions/Date+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Date+Extension.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import Foundation 9 | 10 | extension Date { 11 | func monthToString() -> String { 12 | let dateFormatter = DateFormatter() 13 | dateFormatter.dateFormat = "LLLL" 14 | return dateFormatter.string(from: self) 15 | } 16 | 17 | func toString(format: String) -> String { 18 | let formatter = DateFormatter() 19 | formatter.calendar = Calendar.current 20 | formatter.dateFormat = format 21 | 22 | return formatter.string(from: self) 23 | } 24 | 25 | var yesterday: Date { 26 | Calendar.current.date(byAdding: .day, value: -1, to: self)! 27 | } 28 | 29 | var tomorrow: Date { 30 | Calendar.current.date(byAdding: .day, value: 1, to: self)! 31 | } 32 | 33 | private func isEqual(to date: Date, toGranularity component: Calendar.Component, in calendar: Calendar = .current) -> Bool { 34 | var customCalendar = Calendar(identifier: .gregorian) 35 | customCalendar.firstWeekday = 2 36 | 37 | return customCalendar.isDate(self, equalTo: date, toGranularity: component) 38 | } 39 | 40 | func isInSameWeek(as date: Date) -> Bool { 41 | isEqual(to: date, toGranularity: .weekOfYear) 42 | } 43 | 44 | func isInSameDay(as date: Date) -> Bool { 45 | isEqual(to: date, toGranularity: .day) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Utils/Extensions/View+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // View+Extension.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import Foundation 9 | 10 | import SwiftUI 11 | 12 | extension View { 13 | func cornerRadius(radius: CGFloat, corners: UIRectCorner) -> some View { 14 | ModifiedContent(content: self, modifier: CornerRadiusStyle(radius: radius, corners: corners)) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Utils/MockData/MockTasks.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MockTasks.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import Foundation 9 | 10 | struct MockTasks { 11 | func all() -> [Task] { 12 | [task1, task2, task3, task4, task5, task6, task7, task8, task9, task10, task11, task12, task13, task14, task15, task16, task17] 13 | } 14 | 15 | var task1: Task = .init(iconName: "alarm", 16 | date: Date().addingTimeInterval(-1089), 17 | description: "Wake up!", 18 | isCompleted: true) 19 | 20 | var task2: Task = .init(iconName: "laptopcomputer", 21 | date: Date().addingTimeInterval(-189), 22 | description: "Do work!", 23 | isCompleted: false) 24 | 25 | var task3: Task = .init(iconName: "figure.run", 26 | date: Date().addingTimeInterval(189), 27 | description: "Do sport!", 28 | isCompleted: false) 29 | 30 | var task4: Task = .init(iconName: "moon.zzz", 31 | date: Date().addingTimeInterval(1289), 32 | description: "Sleep well!", 33 | isCompleted: false) 34 | 35 | var task5: Task = .init(iconName: "alarm", 36 | date: Calendar.current.date(byAdding: .day, value: 1, to: Date())!.addingTimeInterval(-1089), 37 | description: "Wake up!", 38 | isCompleted: false) 39 | 40 | var task6: Task = .init(iconName: "web.camera.fill", 41 | date: Calendar.current.date(byAdding: .day, value: 1, to: Date())!.addingTimeInterval(-189), 42 | description: "Attend meeting!", 43 | isCompleted: false) 44 | 45 | var task7: Task = .init(iconName: "bathtub.fill", 46 | date: Calendar.current.date(byAdding: .day, value: 1, to: Date())!, 47 | description: "Take a bath!", 48 | isCompleted: false) 49 | 50 | var task8: Task = .init(iconName: "flag.checkered", 51 | date: Calendar.current.date(byAdding: .day, value: 2, to: Date())!, 52 | description: "Do something!", 53 | isCompleted: false) 54 | 55 | var task9: Task = .init(iconName: "flag.checkered", 56 | date: Calendar.current.date(byAdding: .day, value: 2, to: Date())!, 57 | description: "Do something!", 58 | isCompleted: false) 59 | 60 | var task10: Task = .init(iconName: "flag.checkered", 61 | date: Calendar.current.date(byAdding: .day, value: 3, to: Date())!, 62 | description: "Do something!", 63 | isCompleted: false) 64 | 65 | var task11: Task = .init(iconName: "flag.checkered", 66 | date: Calendar.current.date(byAdding: .day, value: 4, to: Date())!, 67 | description: "Do something!", 68 | isCompleted: false) 69 | 70 | var task12: Task = .init(iconName: "flag.checkered", 71 | date: Calendar.current.date(byAdding: .day, value: 5, to: Date())!, 72 | description: "Do something!", 73 | isCompleted: false) 74 | 75 | var task13: Task = .init(iconName: "flag.checkered", 76 | date: Calendar.current.date(byAdding: .day, value: 6, to: Date())!, 77 | description: "Do something!", 78 | isCompleted: false) 79 | 80 | var task14: Task = .init(iconName: "flag.checkered", 81 | date: Calendar.current.date(byAdding: .day, value: 7, to: Date())!, 82 | description: "Do something!", 83 | isCompleted: false) 84 | 85 | var task15: Task = .init(iconName: "flag.checkered", 86 | date: Calendar.current.date(byAdding: .day, value: 8, to: Date())!, 87 | description: "Do something!", 88 | isCompleted: false) 89 | 90 | var task16: Task = .init(iconName: "flag.checkered", 91 | date: Calendar.current.date(byAdding: .day, value: 9, to: Date())!, 92 | description: "Do something!", 93 | isCompleted: false) 94 | 95 | var task17: Task = .init(iconName: "flag.checkered", 96 | date: Calendar.current.date(byAdding: .day, value: 10, to: Date())!, 97 | description: "Do something!", 98 | isCompleted: false) 99 | } 100 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Utils/Shapes/CornerRadiusShape.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CornerRadiusShape.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct CornerRadiusShape: Shape { 11 | var radius = CGFloat.infinity 12 | var corners = UIRectCorner.allCorners 13 | 14 | func path(in rect: CGRect) -> Path { 15 | let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) 16 | return Path(path.cgPath) 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Utils/ViewModifier/CornerRadiusStyle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CornerRadiusStyle.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct CornerRadiusStyle: ViewModifier { 11 | var radius: CGFloat 12 | var corners: UIRectCorner 13 | 14 | func body(content: Content) -> some View { 15 | content 16 | .clipShape(CornerRadiusShape(radius: radius, corners: corners)) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/ViewModels/TaskViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TaskViewModel.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import Foundation 9 | 10 | class TaskViewModel: ObservableObject { 11 | @Published var task: Task 12 | 13 | init(task: Task) { 14 | self.task = task 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Views/Day/DayView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DayView.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct DayView: View { 11 | let day: Date 12 | var tasks: [Task] 13 | 14 | var body: some View { 15 | VStack { 16 | TaskList(day: day, tasks: tasks) 17 | .frame(maxWidth: .infinity, maxHeight: .infinity) 18 | } 19 | .background(Color.section) 20 | } 21 | } 22 | 23 | struct DayView_Previews: PreviewProvider { 24 | static var previews: some View { 25 | DayView(day: Date(), tasks: [ 26 | .init(iconName: "person", 27 | date: Date(), 28 | description: "Tadaaa 🎉", 29 | isCompleted: false) 30 | ]) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Views/Day/DaysTabView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DaysTabView.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct DaysTabView: View { 11 | @EnvironmentObject var weekStore: WeekStore 12 | 13 | @State private var activeTab: Int = 1 14 | @State private var direction: TimeDirection = .unknown 15 | 16 | let content: (_ day: Date) -> Content 17 | 18 | init(@ViewBuilder content: @escaping (_ day: Date) -> Content) { 19 | self.content = content 20 | } 21 | 22 | var body: some View { 23 | TabView(selection: $activeTab) { 24 | content(weekStore.selectedDate.yesterday) 25 | .frame(maxWidth: .infinity) 26 | .tag(0) 27 | 28 | content(weekStore.selectedDate) 29 | .frame(maxWidth: .infinity) 30 | .tag(1) 31 | .onDisappear() { 32 | if direction != .unknown { 33 | weekStore.select(date: direction == .future ? weekStore.selectedDate.tomorrow : weekStore.selectedDate.yesterday) 34 | } 35 | 36 | direction = .unknown 37 | activeTab = 1 38 | } 39 | 40 | content(weekStore.selectedDate.tomorrow) 41 | .frame(maxWidth: .infinity) 42 | .tag(2) 43 | } 44 | .tabViewStyle(.page(indexDisplayMode: .never)) 45 | .onChange(of: activeTab) { value in 46 | if value == 0 { 47 | direction = .past 48 | } else if value == 2 { 49 | direction = .future 50 | } 51 | } 52 | } 53 | } 54 | 55 | struct DaysTabView_Previews: PreviewProvider { 56 | static var previews: some View { 57 | DaysTabView() { day in 58 | Text(day.toString(format: "EEEE, dd.MM.yyyy")) 59 | }.environmentObject(WeekStore()) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Views/InfiniteWeekView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InfiniteWeekView.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct InfiniteWeekView: View { 11 | @EnvironmentObject var weekStore: WeekStore 12 | 13 | @State var tasks: [Task] = MockTasks().all() 14 | 15 | var body: some View { 16 | GeometryReader { geometry in 17 | NavigationStack { 18 | ZStack { 19 | VStack { 20 | WeekHeaderView() 21 | WeeksTabView() { week in 22 | WeekView(week: week) 23 | } 24 | .frame(height: 80, alignment: .top) 25 | Text(weekStore.selectedDate.toString(format: "EEEE, dd.MM.yyyy")) 26 | .font(.system(size: 10, design: .monospaced)) 27 | .foregroundColor(Color.gray) 28 | DaysTabView() { day in 29 | DayView(day: day, tasks: tasks.filter { $0.date.isInSameDay(as: day) }.sorted(by: { $0.date.timeIntervalSince1970 < $1.date.timeIntervalSince1970 })) 30 | .frame(maxWidth: .infinity, maxHeight: .infinity) 31 | .cornerRadius(radius: 16, corners: [.topLeft, .topRight]) 32 | .ignoresSafeArea() 33 | .listRowBackground(Color.clear) 34 | .padding([.leading, .trailing], 10) 35 | } 36 | .ignoresSafeArea() 37 | .frame(idealHeight: .infinity) 38 | } 39 | VStack { 40 | Spacer() 41 | HStack { 42 | Spacer() 43 | NavigationLink { 44 | NewTaskForm(tasks: $tasks) 45 | .navigationBarTitleDisplayMode(.large) 46 | } label: { 47 | Image(systemName: "plus.circle.fill") 48 | .font(.system(size: 50)) 49 | .foregroundColor(.accentColor) 50 | } 51 | .padding() 52 | } 53 | } 54 | } 55 | } 56 | } 57 | } 58 | } 59 | 60 | struct InfinityTabPageWrapperView_Previews: PreviewProvider { 61 | static var previews: some View { 62 | InfiniteWeekView() 63 | .environmentObject(WeekStore()) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Views/Task/NewTaskForm.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewTaskForm.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct NewTaskForm: View { 11 | @Binding var tasks: [Task] 12 | 13 | @State private var name: String = "" 14 | @State private var date: String = "20.03.2023" 15 | @State private var imageName: String = "lightbulb.fill" 16 | @State private var description: String = "" 17 | 18 | var body: some View { 19 | VStack { 20 | Form { 21 | Section(header: Text("Title")) { 22 | TextField("Enter a title", text: $name) 23 | .padding() 24 | } 25 | 26 | Section(header: Text("Date")) { 27 | HStack { 28 | Text("Select a date:") 29 | Spacer() 30 | .frame(width: 40) 31 | ZStack { 32 | Rectangle() 33 | .foregroundColor(Color(UIColor.darkGray)) 34 | .cornerRadius(radius: 8, corners: .allCorners) 35 | Text(date) 36 | } 37 | } 38 | } 39 | 40 | Section(header: Text("Image")) { 41 | HStack { 42 | Text("Select an image:") 43 | Spacer() 44 | ZStack { 45 | Circle() 46 | .foregroundColor(Color(UIColor.darkGray)) 47 | .frame(width: 65) 48 | Image(systemName: imageName) 49 | .font(.system(size: 30)) 50 | .foregroundColor(.primary) 51 | } 52 | } 53 | } 54 | } 55 | 56 | Button(action: { 57 | tasks.append(.init(iconName: imageName, 58 | date: Date(), 59 | description: name, 60 | isCompleted: false)) 61 | }, label: { 62 | Label("Create", systemImage: "plus.circle") 63 | .font(.system(size: 20)) 64 | }) 65 | .buttonStyle(.borderedProminent) 66 | .padding(.bottom, 10) 67 | } 68 | .navigationTitle("Create new task") 69 | } 70 | } 71 | 72 | struct NewTaskForm_Previews: PreviewProvider { 73 | static var previews: some View { 74 | NewTaskForm(tasks: .constant([.init(iconName: "person", date: Date(), description: "Description", isCompleted: false)])) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Views/Task/TaskCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TaskCell.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct TaskCell: View { 11 | @StateObject var taskVM: TaskViewModel 12 | 13 | var body: some View { 14 | HStack { 15 | Text(taskVM.task.date.toString(format: "hh:mm")) 16 | .font(.system(size: 10, design: .monospaced)) 17 | ZStack { 18 | Circle() 19 | .foregroundColor(Color.element) 20 | .frame(width: 45) 21 | Image(systemName: taskVM.task.iconName) 22 | .font(.system(size: 23)) 23 | .foregroundColor(.primary) 24 | } 25 | Spacer() 26 | .frame(width: 10) 27 | Text(taskVM.task.description) 28 | .strikethrough(taskVM.task.isCompleted) 29 | .font(.system(size: 16)) 30 | Spacer() 31 | Image(systemName: taskVM.task.isCompleted ? "checkmark.circle.fill" : "circle") 32 | .font(.system(size: 20)) 33 | .foregroundColor(taskVM.task.isCompleted ? .green : .primary) 34 | } 35 | .background(.clear) 36 | .onTapGesture { 37 | withAnimation { 38 | taskVM.task.isCompleted.toggle() 39 | } 40 | } 41 | } 42 | } 43 | 44 | struct TaskCell_Previews: PreviewProvider { 45 | static var previews: some View { 46 | TaskCell(taskVM: .init(task: .init(iconName: "flag.checkered", date: Date(), description: "Do something!", isCompleted: false))) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Views/Task/TaskList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TaskList.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct TaskList: View { 11 | let day: Date 12 | var tasks: [Task] 13 | 14 | var body: some View { 15 | ZStack { 16 | if tasks.isEmpty { 17 | Text("No tasks today") 18 | .font(.system(size: 18)) 19 | } else { 20 | VStack { 21 | List { 22 | ForEach(tasks) { task in 23 | TaskCell(taskVM: .init(task: task)) 24 | .listRowBackground(Color.clear) 25 | .listRowSeparator(.hidden) 26 | } 27 | } 28 | .listStyle(.plain) 29 | .onAppear() { 30 | UITableView.appearance().backgroundColor = UIColor.clear 31 | UITableViewCell.appearance().backgroundColor = UIColor.clear 32 | } 33 | } 34 | .ignoresSafeArea() 35 | } 36 | } 37 | } 38 | } 39 | 40 | struct TaskList_Previews: PreviewProvider { 41 | static var previews: some View { 42 | TaskList(day: Date(), tasks: []) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Views/Week/WeekHeaderView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WeekHeaderView.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct WeekHeaderView: View { 11 | @EnvironmentObject var weekStore: WeekStore 12 | @State var showDatePicker: Bool = false 13 | 14 | var body: some View { 15 | HStack { 16 | Text(weekStore.selectedDate.monthToString()) 17 | .font(.system(size: 24)) 18 | .fontWeight(.heavy) 19 | .foregroundColor(.accentColor) 20 | Text(weekStore.selectedDate.toString(format: "yyyy")) 21 | .font(.system(size: 24)) 22 | .fontWeight(.semibold) 23 | Spacer() 24 | Button { 25 | withAnimation { 26 | weekStore.selectToday() 27 | } 28 | } label: { 29 | Text("Today") 30 | .font(.system(size: 14)) 31 | .fontWeight(.semibold) 32 | .foregroundColor(.primary) 33 | .padding(4) 34 | .background(.secondary) 35 | .cornerRadius(4) 36 | } 37 | Button { 38 | showDatePicker = true 39 | } label: { 40 | Image(systemName: "calendar") 41 | .font(.system(size: 24)) 42 | .foregroundColor(.primary) 43 | } 44 | .sheet(isPresented: $showDatePicker) { 45 | VStack { 46 | DatePicker("Select Date", selection: $weekStore.selectedDate) 47 | .datePickerStyle(GraphicalDatePickerStyle()) 48 | .cornerRadius(15) 49 | .shadow(color: .black, radius: 5) 50 | .padding() 51 | .presentationDetents([.height(400), .fraction(20), .medium, .large]) 52 | .onChange(of: weekStore.selectedDate, perform: { _ in 53 | showDatePicker = false 54 | }) 55 | } 56 | } 57 | } 58 | .padding(.init(top: 5, leading: 10, bottom: -3, trailing: 8)) 59 | } 60 | } 61 | 62 | struct WeekHeaderView_Previews: PreviewProvider { 63 | static var previews: some View { 64 | WeekHeaderView() 65 | .environmentObject(WeekStore()) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Views/Week/WeekView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WeekView.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct WeekView: View { 11 | @EnvironmentObject var weekStore: WeekStore 12 | 13 | var week: Week 14 | 15 | var body: some View { 16 | HStack { 17 | ForEach(0..<7) { i in 18 | VStack { 19 | Text(week.dates[i].toString(format: "EEE").uppercased()) 20 | .font(.system(size: 16)) 21 | .fontWeight(.semibold) 22 | .frame(maxWidth:.infinity) 23 | Spacer() 24 | .frame(height: 4) 25 | ZStack { 26 | HStack{ 27 | Spacer() 28 | .frame(width: 5) 29 | Circle() 30 | .foregroundColor(week.dates[i] == week.referenceDate ? .accentColor : .clear) 31 | Spacer() 32 | .frame(width: 5) 33 | } 34 | Text(week.dates[i].toString(format: "d")) 35 | .font(.system(size: 16)) 36 | .monospaced() 37 | .frame(maxWidth: .infinity) 38 | .foregroundColor(week.dates[i] == week.referenceDate ? .white : .primary) 39 | } 40 | }.onTapGesture { 41 | withAnimation { 42 | weekStore.selectedDate = week.dates[i] 43 | } 44 | } 45 | .frame(maxWidth: .infinity) 46 | } 47 | } 48 | .padding() 49 | } 50 | } 51 | 52 | struct WeekView_Previews: PreviewProvider { 53 | static var previews: some View { 54 | WeekView(week: .init(index: 1, dates: 55 | [ 56 | Date().yesterday.yesterday.yesterday, 57 | Date().yesterday.yesterday, 58 | Date().yesterday, 59 | Date(), 60 | Date().tomorrow, 61 | Date().tomorrow.tomorrow, 62 | Date().tomorrow.tomorrow.tomorrow 63 | ], 64 | referenceDate: Date())) 65 | .environmentObject(WeekStore()) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /InfiniteWeekView/InfiniteWeekView/Views/Week/WeeksTabView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WeeksTabView.swift 3 | // InfiniteWeekView 4 | // 5 | // Created by Philipp Knoblauch on 13.05.23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct WeeksTabView: View { 11 | @EnvironmentObject var weekStore: WeekStore 12 | 13 | @State private var activeTab: Int = 1 14 | @State private var direction: TimeDirection = .unknown 15 | @State private var position = CGSize.zero 16 | @GestureState private var dragOffset = CGSize.zero 17 | 18 | let content: (_ week: Week) -> Content 19 | 20 | init(@ViewBuilder content: @escaping (_ week: Week) -> Content) { 21 | self.content = content 22 | } 23 | 24 | var body: some View { 25 | TabView(selection: $activeTab) { 26 | content(weekStore.weeks[0]) 27 | .frame(maxWidth: .infinity) 28 | .tag(0) 29 | 30 | content(weekStore.weeks[1]) 31 | .frame(maxWidth: .infinity) 32 | .tag(1) 33 | .onDisappear() { 34 | guard direction != .unknown else { return } 35 | weekStore.update(to: direction) 36 | direction = .unknown 37 | activeTab = 1 38 | } 39 | 40 | content(weekStore.weeks[2]) 41 | .frame(maxWidth: .infinity) 42 | .tag(2) 43 | } 44 | .tabViewStyle(.page(indexDisplayMode: .never)) 45 | .onChange(of: activeTab) { value in 46 | if value == 0 { 47 | direction = .past 48 | } else if value == 2 { 49 | direction = .future 50 | } 51 | } 52 | } 53 | } 54 | 55 | struct WeeksTabView_Previews: PreviewProvider { 56 | static var previews: some View { 57 | WeeksTabView() { week in 58 | WeekView(week: week) 59 | }.environmentObject(WeekStore()) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # InfiniteWeekView 2 | Infinite swipeable week view with day detail view in SwiftUI 3 | 4 | 5 | https://github.com/philippkno/InfiniteWeekView/assets/20753878/43e429f1-5285-40b2-adee-bfe0c3139f19 6 | 7 | 8 | 9 | 10 | --------------------------------------------------------------------------------