├── .gitignore ├── README.md ├── StudyGroupEventFetcherForSwiftUI.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── milanista.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── StudyGroupEventFetcherForSwiftUI ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── app_icon1024.png │ │ ├── app_icon120-1.png │ │ ├── app_icon120.png │ │ ├── app_icon152.png │ │ ├── app_icon167.png │ │ ├── app_icon180.png │ │ ├── app_icon20.png │ │ ├── app_icon29.png │ │ ├── app_icon40-1.png │ │ ├── app_icon40-2.png │ │ ├── app_icon40.png │ │ ├── app_icon58-1.png │ │ ├── app_icon58.png │ │ ├── app_icon60.png │ │ ├── app_icon76.png │ │ ├── app_icon80-1.png │ │ ├── app_icon80.png │ │ └── app_icon87.png │ ├── Contents.json │ └── Detail │ │ ├── Contents.json │ │ └── img_yumemi_swift.imageset │ │ ├── Contents.json │ │ └── img_yumemi_swift.png ├── Base.lproj │ └── LaunchScreen.storyboard ├── Info.plist ├── Model │ ├── Event.swift │ ├── PinItem.swift │ └── StudyGroup.swift ├── Other │ ├── APIError.swift │ ├── StudyGroupDateFormatter.swift │ └── StudyGroupEventFetcher.swift ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── StudyGroupEventFetcherForSwiftUIApp.swift ├── ViewModel │ └── TopListViewModel.swift └── Views │ ├── Common │ ├── LoadingView.swift │ └── LoadingViewModifier.swift │ ├── EventDetail │ ├── EventDetailButtonView.swift │ ├── EventDetailMapButtonView.swift │ ├── EventDetailPartView.swift │ └── EventDetailView.swift │ ├── Map │ └── NewMapView.swift │ ├── Safari │ └── SafariView.swift │ └── TopEventList │ ├── EventLabelView.swift │ ├── EventRowView.swift │ └── TopListView.swift ├── StudyGroupEventFetcherForSwiftUITests ├── Info.plist └── StudyGroupEventFetcherForSwiftUITests.swift └── StudyGroupEventFetcherForSwiftUIUITests ├── Info.plist └── StudyGroupEventFetcherForSwiftUIUITests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | project.xcworkspace/ 2 | xcuserdata/ 3 | build/ 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # StudyGroupEventFetcherForSwiftUI 2 | 3 | This is a sample project of SwiftUI that displays the data obtained via external API in "List". 4 | This App fetches study group event list via connpass API. 5 | For example, YUMEMI.swift. We hold on a regular basis. 6 | 7 | ## Qiita 8 | 9 | Wrote article. 10 | 11 | [https://qiita.com/MilanistaDev/items/64dca8c9d5099a19529e](https://qiita.com/MilanistaDev/items/64dca8c9d5099a19529e) 12 | 13 | ### iOS 16 Support 14 | 15 | [https://qiita.com/MilanistaDev/items/fce3987b02a284f5112a](https://qiita.com/MilanistaDev/items/fce3987b02a284f5112a) 16 | 17 | ## Enjoy SwiftUI vol2 18 | 19 | This sample is for live coding of Enjoy SwiftUI vol2. 20 | The event link is as bellow. 21 | 22 | https://yumemi.connpass.com/event/151594/ 23 | 24 | ## connpass Event Search API 25 | 26 | **Request URL** 27 | `https://connpass.com/api/v1/event/` 28 | 29 | This sample code's Link is follow. 30 | `https://connpass.com/api/v1/event/?keyword=YUMEMI.swift` 31 | 32 | If you'd like to browse the detail of this API, please access this link. 33 | [https://connpass.com/about/api/](https://connpass.com/about/api/) 34 | 35 | ## Run this code 36 | ![RPReplay_Final1577106112](https://user-images.githubusercontent.com/8732417/71359508-f9f0fe80-25cf-11ea-8d64-84f4a79a2892.gif) 37 | 38 | 39 | ## Support 40 | * macOS Catalina 10.15.1 and later 41 | * Xcode 11.2.1 and later 42 | 43 | ## App update history 44 | 45 | |App Version|Date|MEMO| 46 | |:--:|:--:|:--| 47 | |1.0|2019-11-08|v1.0 released.| 48 | |1.0.1|2019-12-23|Implemented DetailView Screen.| 49 | |1.0.2|2020-04-14|Fixed a bug that the list is not displayed
when there is no location information of the event.| 50 | |1.0.3|2020-06-24|Add zoom-in and out buttons on the MapVew. Fixed a bug. Some refactorings.| 51 | 52 | ## Contact 53 | 54 | Please feel free to contact us if you find a bug or have any feedback. 55 | Suggestions for adding functions and code corrections are also welcome. 56 | 57 | ```swift 58 | let name = "Takuya Aso" 59 | let email = "milanista224" + "@" + "icloud.com" 60 | let profession = "iOS Engineer" 61 | let location = "Tokyo" 62 | ``` 63 | 64 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | FD0506D1236C46A4003260B9 /* StudyGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0506D0236C46A4003260B9 /* StudyGroup.swift */; }; 11 | FD0506D3236C471E003260B9 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0506D2236C471E003260B9 /* Event.swift */; }; 12 | FD0506D6236C4A8F003260B9 /* TopListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0506D5236C4A8F003260B9 /* TopListView.swift */; }; 13 | FD0506D8236C4FA5003260B9 /* EventRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0506D7236C4FA5003260B9 /* EventRowView.swift */; }; 14 | FD0506DA23712219003260B9 /* EventDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0506D923712219003260B9 /* EventDetailView.swift */; }; 15 | FD0506DC2371282C003260B9 /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0506DB2371282C003260B9 /* SafariView.swift */; }; 16 | FD50073623AFBEEE00C369EF /* EventDetailPartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD50073523AFBEEE00C369EF /* EventDetailPartView.swift */; }; 17 | FD50ECAD23717D3B00BC8342 /* TopListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD50ECAC23717D3B00BC8342 /* TopListViewModel.swift */; }; 18 | FD525C65237133AE00F9C171 /* StudyGroupEventFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD525C64237133AE00F9C171 /* StudyGroupEventFetcher.swift */; }; 19 | FD794B6D2462D35B00C000CD /* EventDetailMapButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD794B6C2462D35B00C000CD /* EventDetailMapButtonView.swift */; }; 20 | FD9E6FD6294D61B000979FFF /* LoadingViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9E6FD5294D61B000979FFF /* LoadingViewModifier.swift */; }; 21 | FD9E6FDE29504D5A00979FFF /* PinItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9E6FDD29504D5A00979FFF /* PinItem.swift */; }; 22 | FD9E6FE029504FE000979FFF /* NewMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9E6FDF29504FE000979FFF /* NewMapView.swift */; }; 23 | FD9E6FE42952BB3400979FFF /* APIError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9E6FE32952BB3400979FFF /* APIError.swift */; }; 24 | FD9E6FE62953260500979FFF /* StudyGroupEventFetcherForSwiftUIApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9E6FE52953260500979FFF /* StudyGroupEventFetcherForSwiftUIApp.swift */; }; 25 | FD9EB141236C33EF00DD6367 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FD9EB140236C33EF00DD6367 /* Assets.xcassets */; }; 26 | FD9EB144236C33EF00DD6367 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FD9EB143236C33EF00DD6367 /* Preview Assets.xcassets */; }; 27 | FD9EB147236C33EF00DD6367 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FD9EB145236C33EF00DD6367 /* LaunchScreen.storyboard */; }; 28 | FD9EB152236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9EB151236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUITests.swift */; }; 29 | FD9EB15D236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUIUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9EB15C236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUIUITests.swift */; }; 30 | FDA2705C24A7873A009A8505 /* EventLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDA2705B24A7873A009A8505 /* EventLabelView.swift */; }; 31 | FDAE1B78237173C900217BD1 /* StudyGroupDateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDAE1B77237173C900217BD1 /* StudyGroupDateFormatter.swift */; }; 32 | FDEA054024ADE2B700AC44EC /* LoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDEA053F24ADE2B700AC44EC /* LoadingView.swift */; }; 33 | FDF7EB90244B2B3000BF1A6E /* EventDetailButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF7EB8F244B2B3000BF1A6E /* EventDetailButtonView.swift */; }; 34 | /* End PBXBuildFile section */ 35 | 36 | /* Begin PBXContainerItemProxy section */ 37 | FD9EB14E236C33EF00DD6367 /* PBXContainerItemProxy */ = { 38 | isa = PBXContainerItemProxy; 39 | containerPortal = FD9EB12F236C33EE00DD6367 /* Project object */; 40 | proxyType = 1; 41 | remoteGlobalIDString = FD9EB136236C33EE00DD6367; 42 | remoteInfo = StudyGroupEventFetcherForSwiftUI; 43 | }; 44 | FD9EB159236C33EF00DD6367 /* PBXContainerItemProxy */ = { 45 | isa = PBXContainerItemProxy; 46 | containerPortal = FD9EB12F236C33EE00DD6367 /* Project object */; 47 | proxyType = 1; 48 | remoteGlobalIDString = FD9EB136236C33EE00DD6367; 49 | remoteInfo = StudyGroupEventFetcherForSwiftUI; 50 | }; 51 | /* End PBXContainerItemProxy section */ 52 | 53 | /* Begin PBXFileReference section */ 54 | FD0506D0236C46A4003260B9 /* StudyGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudyGroup.swift; sourceTree = ""; }; 55 | FD0506D2236C471E003260B9 /* Event.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Event.swift; sourceTree = ""; }; 56 | FD0506D5236C4A8F003260B9 /* TopListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopListView.swift; sourceTree = ""; }; 57 | FD0506D7236C4FA5003260B9 /* EventRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventRowView.swift; sourceTree = ""; }; 58 | FD0506D923712219003260B9 /* EventDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventDetailView.swift; sourceTree = ""; }; 59 | FD0506DB2371282C003260B9 /* SafariView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariView.swift; sourceTree = ""; }; 60 | FD50073523AFBEEE00C369EF /* EventDetailPartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventDetailPartView.swift; sourceTree = ""; }; 61 | FD50ECAC23717D3B00BC8342 /* TopListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopListViewModel.swift; sourceTree = ""; }; 62 | FD525C64237133AE00F9C171 /* StudyGroupEventFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudyGroupEventFetcher.swift; sourceTree = ""; }; 63 | FD794B6C2462D35B00C000CD /* EventDetailMapButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventDetailMapButtonView.swift; sourceTree = ""; }; 64 | FD9E6FD5294D61B000979FFF /* LoadingViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingViewModifier.swift; sourceTree = ""; }; 65 | FD9E6FDD29504D5A00979FFF /* PinItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinItem.swift; sourceTree = ""; }; 66 | FD9E6FDF29504FE000979FFF /* NewMapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewMapView.swift; sourceTree = ""; }; 67 | FD9E6FE32952BB3400979FFF /* APIError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIError.swift; sourceTree = ""; }; 68 | FD9E6FE52953260500979FFF /* StudyGroupEventFetcherForSwiftUIApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudyGroupEventFetcherForSwiftUIApp.swift; sourceTree = ""; }; 69 | FD9EB137236C33EE00DD6367 /* StudyGroupEventFetcherForSwiftUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StudyGroupEventFetcherForSwiftUI.app; sourceTree = BUILT_PRODUCTS_DIR; }; 70 | FD9EB140236C33EF00DD6367 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 71 | FD9EB143236C33EF00DD6367 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 72 | FD9EB146236C33EF00DD6367 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 73 | FD9EB148236C33EF00DD6367 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 74 | FD9EB14D236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StudyGroupEventFetcherForSwiftUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 75 | FD9EB151236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudyGroupEventFetcherForSwiftUITests.swift; sourceTree = ""; }; 76 | FD9EB153236C33EF00DD6367 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 77 | FD9EB158236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUIUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StudyGroupEventFetcherForSwiftUIUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 78 | FD9EB15C236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUIUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudyGroupEventFetcherForSwiftUIUITests.swift; sourceTree = ""; }; 79 | FD9EB15E236C33EF00DD6367 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 80 | FDA2705B24A7873A009A8505 /* EventLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventLabelView.swift; sourceTree = ""; }; 81 | FDAE1B77237173C900217BD1 /* StudyGroupDateFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StudyGroupDateFormatter.swift; sourceTree = ""; }; 82 | FDEA053F24ADE2B700AC44EC /* LoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingView.swift; sourceTree = ""; }; 83 | FDF7EB8F244B2B3000BF1A6E /* EventDetailButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventDetailButtonView.swift; sourceTree = ""; }; 84 | /* End PBXFileReference section */ 85 | 86 | /* Begin PBXFrameworksBuildPhase section */ 87 | FD9EB134236C33EE00DD6367 /* Frameworks */ = { 88 | isa = PBXFrameworksBuildPhase; 89 | buildActionMask = 2147483647; 90 | files = ( 91 | ); 92 | runOnlyForDeploymentPostprocessing = 0; 93 | }; 94 | FD9EB14A236C33EF00DD6367 /* Frameworks */ = { 95 | isa = PBXFrameworksBuildPhase; 96 | buildActionMask = 2147483647; 97 | files = ( 98 | ); 99 | runOnlyForDeploymentPostprocessing = 0; 100 | }; 101 | FD9EB155236C33EF00DD6367 /* Frameworks */ = { 102 | isa = PBXFrameworksBuildPhase; 103 | buildActionMask = 2147483647; 104 | files = ( 105 | ); 106 | runOnlyForDeploymentPostprocessing = 0; 107 | }; 108 | /* End PBXFrameworksBuildPhase section */ 109 | 110 | /* Begin PBXGroup section */ 111 | FD0506CF236C4662003260B9 /* Model */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | FD0506D0236C46A4003260B9 /* StudyGroup.swift */, 115 | FD0506D2236C471E003260B9 /* Event.swift */, 116 | FD9E6FDD29504D5A00979FFF /* PinItem.swift */, 117 | ); 118 | path = Model; 119 | sourceTree = ""; 120 | }; 121 | FD0506D4236C4A70003260B9 /* Views */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | FDEA053E24ADE2A000AC44EC /* Common */, 125 | FD50073223AFBDE700C369EF /* TopEventList */, 126 | FD50073323AFBDFC00C369EF /* EventDetail */, 127 | FD50073723AFC29000C369EF /* Map */, 128 | FD50073423AFBE1300C369EF /* Safari */, 129 | ); 130 | path = Views; 131 | sourceTree = ""; 132 | }; 133 | FD50073223AFBDE700C369EF /* TopEventList */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | FD0506D5236C4A8F003260B9 /* TopListView.swift */, 137 | FD0506D7236C4FA5003260B9 /* EventRowView.swift */, 138 | FDA2705B24A7873A009A8505 /* EventLabelView.swift */, 139 | ); 140 | path = TopEventList; 141 | sourceTree = ""; 142 | }; 143 | FD50073323AFBDFC00C369EF /* EventDetail */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | FD0506D923712219003260B9 /* EventDetailView.swift */, 147 | FD794B6C2462D35B00C000CD /* EventDetailMapButtonView.swift */, 148 | FD50073523AFBEEE00C369EF /* EventDetailPartView.swift */, 149 | FDF7EB8F244B2B3000BF1A6E /* EventDetailButtonView.swift */, 150 | ); 151 | path = EventDetail; 152 | sourceTree = ""; 153 | }; 154 | FD50073423AFBE1300C369EF /* Safari */ = { 155 | isa = PBXGroup; 156 | children = ( 157 | FD0506DB2371282C003260B9 /* SafariView.swift */, 158 | ); 159 | path = Safari; 160 | sourceTree = ""; 161 | }; 162 | FD50073723AFC29000C369EF /* Map */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | FD9E6FDF29504FE000979FFF /* NewMapView.swift */, 166 | ); 167 | path = Map; 168 | sourceTree = ""; 169 | }; 170 | FD50ECAB23717D1900BC8342 /* ViewModel */ = { 171 | isa = PBXGroup; 172 | children = ( 173 | FD50ECAC23717D3B00BC8342 /* TopListViewModel.swift */, 174 | ); 175 | path = ViewModel; 176 | sourceTree = ""; 177 | }; 178 | FD525C632371338100F9C171 /* Other */ = { 179 | isa = PBXGroup; 180 | children = ( 181 | FD525C64237133AE00F9C171 /* StudyGroupEventFetcher.swift */, 182 | FDAE1B77237173C900217BD1 /* StudyGroupDateFormatter.swift */, 183 | FD9E6FE32952BB3400979FFF /* APIError.swift */, 184 | ); 185 | path = Other; 186 | sourceTree = ""; 187 | }; 188 | FD9EB12E236C33EE00DD6367 = { 189 | isa = PBXGroup; 190 | children = ( 191 | FD9EB139236C33EE00DD6367 /* StudyGroupEventFetcherForSwiftUI */, 192 | FD9EB150236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUITests */, 193 | FD9EB15B236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUIUITests */, 194 | FD9EB138236C33EE00DD6367 /* Products */, 195 | ); 196 | sourceTree = ""; 197 | }; 198 | FD9EB138236C33EE00DD6367 /* Products */ = { 199 | isa = PBXGroup; 200 | children = ( 201 | FD9EB137236C33EE00DD6367 /* StudyGroupEventFetcherForSwiftUI.app */, 202 | FD9EB14D236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUITests.xctest */, 203 | FD9EB158236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUIUITests.xctest */, 204 | ); 205 | name = Products; 206 | sourceTree = ""; 207 | }; 208 | FD9EB139236C33EE00DD6367 /* StudyGroupEventFetcherForSwiftUI */ = { 209 | isa = PBXGroup; 210 | children = ( 211 | FD9E6FE52953260500979FFF /* StudyGroupEventFetcherForSwiftUIApp.swift */, 212 | FD0506D4236C4A70003260B9 /* Views */, 213 | FD50ECAB23717D1900BC8342 /* ViewModel */, 214 | FD0506CF236C4662003260B9 /* Model */, 215 | FD525C632371338100F9C171 /* Other */, 216 | FD9EB140236C33EF00DD6367 /* Assets.xcassets */, 217 | FD9EB145236C33EF00DD6367 /* LaunchScreen.storyboard */, 218 | FD9EB148236C33EF00DD6367 /* Info.plist */, 219 | FD9EB142236C33EF00DD6367 /* Preview Content */, 220 | ); 221 | path = StudyGroupEventFetcherForSwiftUI; 222 | sourceTree = ""; 223 | }; 224 | FD9EB142236C33EF00DD6367 /* Preview Content */ = { 225 | isa = PBXGroup; 226 | children = ( 227 | FD9EB143236C33EF00DD6367 /* Preview Assets.xcassets */, 228 | ); 229 | path = "Preview Content"; 230 | sourceTree = ""; 231 | }; 232 | FD9EB150236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUITests */ = { 233 | isa = PBXGroup; 234 | children = ( 235 | FD9EB151236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUITests.swift */, 236 | FD9EB153236C33EF00DD6367 /* Info.plist */, 237 | ); 238 | path = StudyGroupEventFetcherForSwiftUITests; 239 | sourceTree = ""; 240 | }; 241 | FD9EB15B236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUIUITests */ = { 242 | isa = PBXGroup; 243 | children = ( 244 | FD9EB15C236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUIUITests.swift */, 245 | FD9EB15E236C33EF00DD6367 /* Info.plist */, 246 | ); 247 | path = StudyGroupEventFetcherForSwiftUIUITests; 248 | sourceTree = ""; 249 | }; 250 | FDEA053E24ADE2A000AC44EC /* Common */ = { 251 | isa = PBXGroup; 252 | children = ( 253 | FDEA053F24ADE2B700AC44EC /* LoadingView.swift */, 254 | FD9E6FD5294D61B000979FFF /* LoadingViewModifier.swift */, 255 | ); 256 | path = Common; 257 | sourceTree = ""; 258 | }; 259 | /* End PBXGroup section */ 260 | 261 | /* Begin PBXNativeTarget section */ 262 | FD9EB136236C33EE00DD6367 /* StudyGroupEventFetcherForSwiftUI */ = { 263 | isa = PBXNativeTarget; 264 | buildConfigurationList = FD9EB161236C33EF00DD6367 /* Build configuration list for PBXNativeTarget "StudyGroupEventFetcherForSwiftUI" */; 265 | buildPhases = ( 266 | FD9EB133236C33EE00DD6367 /* Sources */, 267 | FD9EB134236C33EE00DD6367 /* Frameworks */, 268 | FD9EB135236C33EE00DD6367 /* Resources */, 269 | ); 270 | buildRules = ( 271 | ); 272 | dependencies = ( 273 | ); 274 | name = StudyGroupEventFetcherForSwiftUI; 275 | productName = StudyGroupEventFetcherForSwiftUI; 276 | productReference = FD9EB137236C33EE00DD6367 /* StudyGroupEventFetcherForSwiftUI.app */; 277 | productType = "com.apple.product-type.application"; 278 | }; 279 | FD9EB14C236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUITests */ = { 280 | isa = PBXNativeTarget; 281 | buildConfigurationList = FD9EB164236C33EF00DD6367 /* Build configuration list for PBXNativeTarget "StudyGroupEventFetcherForSwiftUITests" */; 282 | buildPhases = ( 283 | FD9EB149236C33EF00DD6367 /* Sources */, 284 | FD9EB14A236C33EF00DD6367 /* Frameworks */, 285 | FD9EB14B236C33EF00DD6367 /* Resources */, 286 | ); 287 | buildRules = ( 288 | ); 289 | dependencies = ( 290 | FD9EB14F236C33EF00DD6367 /* PBXTargetDependency */, 291 | ); 292 | name = StudyGroupEventFetcherForSwiftUITests; 293 | productName = StudyGroupEventFetcherForSwiftUITests; 294 | productReference = FD9EB14D236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUITests.xctest */; 295 | productType = "com.apple.product-type.bundle.unit-test"; 296 | }; 297 | FD9EB157236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUIUITests */ = { 298 | isa = PBXNativeTarget; 299 | buildConfigurationList = FD9EB167236C33EF00DD6367 /* Build configuration list for PBXNativeTarget "StudyGroupEventFetcherForSwiftUIUITests" */; 300 | buildPhases = ( 301 | FD9EB154236C33EF00DD6367 /* Sources */, 302 | FD9EB155236C33EF00DD6367 /* Frameworks */, 303 | FD9EB156236C33EF00DD6367 /* Resources */, 304 | ); 305 | buildRules = ( 306 | ); 307 | dependencies = ( 308 | FD9EB15A236C33EF00DD6367 /* PBXTargetDependency */, 309 | ); 310 | name = StudyGroupEventFetcherForSwiftUIUITests; 311 | productName = StudyGroupEventFetcherForSwiftUIUITests; 312 | productReference = FD9EB158236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUIUITests.xctest */; 313 | productType = "com.apple.product-type.bundle.ui-testing"; 314 | }; 315 | /* End PBXNativeTarget section */ 316 | 317 | /* Begin PBXProject section */ 318 | FD9EB12F236C33EE00DD6367 /* Project object */ = { 319 | isa = PBXProject; 320 | attributes = { 321 | LastSwiftUpdateCheck = 1100; 322 | LastUpgradeCheck = 1100; 323 | ORGANIZATIONNAME = "Takuya Aso"; 324 | TargetAttributes = { 325 | FD9EB136236C33EE00DD6367 = { 326 | CreatedOnToolsVersion = 11.0; 327 | }; 328 | FD9EB14C236C33EF00DD6367 = { 329 | CreatedOnToolsVersion = 11.0; 330 | TestTargetID = FD9EB136236C33EE00DD6367; 331 | }; 332 | FD9EB157236C33EF00DD6367 = { 333 | CreatedOnToolsVersion = 11.0; 334 | TestTargetID = FD9EB136236C33EE00DD6367; 335 | }; 336 | }; 337 | }; 338 | buildConfigurationList = FD9EB132236C33EE00DD6367 /* Build configuration list for PBXProject "StudyGroupEventFetcherForSwiftUI" */; 339 | compatibilityVersion = "Xcode 9.3"; 340 | developmentRegion = en; 341 | hasScannedForEncodings = 0; 342 | knownRegions = ( 343 | en, 344 | Base, 345 | ); 346 | mainGroup = FD9EB12E236C33EE00DD6367; 347 | productRefGroup = FD9EB138236C33EE00DD6367 /* Products */; 348 | projectDirPath = ""; 349 | projectRoot = ""; 350 | targets = ( 351 | FD9EB136236C33EE00DD6367 /* StudyGroupEventFetcherForSwiftUI */, 352 | FD9EB14C236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUITests */, 353 | FD9EB157236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUIUITests */, 354 | ); 355 | }; 356 | /* End PBXProject section */ 357 | 358 | /* Begin PBXResourcesBuildPhase section */ 359 | FD9EB135236C33EE00DD6367 /* Resources */ = { 360 | isa = PBXResourcesBuildPhase; 361 | buildActionMask = 2147483647; 362 | files = ( 363 | FD9EB147236C33EF00DD6367 /* LaunchScreen.storyboard in Resources */, 364 | FD9EB144236C33EF00DD6367 /* Preview Assets.xcassets in Resources */, 365 | FD9EB141236C33EF00DD6367 /* Assets.xcassets in Resources */, 366 | ); 367 | runOnlyForDeploymentPostprocessing = 0; 368 | }; 369 | FD9EB14B236C33EF00DD6367 /* Resources */ = { 370 | isa = PBXResourcesBuildPhase; 371 | buildActionMask = 2147483647; 372 | files = ( 373 | ); 374 | runOnlyForDeploymentPostprocessing = 0; 375 | }; 376 | FD9EB156236C33EF00DD6367 /* Resources */ = { 377 | isa = PBXResourcesBuildPhase; 378 | buildActionMask = 2147483647; 379 | files = ( 380 | ); 381 | runOnlyForDeploymentPostprocessing = 0; 382 | }; 383 | /* End PBXResourcesBuildPhase section */ 384 | 385 | /* Begin PBXSourcesBuildPhase section */ 386 | FD9EB133236C33EE00DD6367 /* Sources */ = { 387 | isa = PBXSourcesBuildPhase; 388 | buildActionMask = 2147483647; 389 | files = ( 390 | FDF7EB90244B2B3000BF1A6E /* EventDetailButtonView.swift in Sources */, 391 | FD9E6FDE29504D5A00979FFF /* PinItem.swift in Sources */, 392 | FD0506D8236C4FA5003260B9 /* EventRowView.swift in Sources */, 393 | FDAE1B78237173C900217BD1 /* StudyGroupDateFormatter.swift in Sources */, 394 | FDEA054024ADE2B700AC44EC /* LoadingView.swift in Sources */, 395 | FD50ECAD23717D3B00BC8342 /* TopListViewModel.swift in Sources */, 396 | FD9E6FD6294D61B000979FFF /* LoadingViewModifier.swift in Sources */, 397 | FD0506D1236C46A4003260B9 /* StudyGroup.swift in Sources */, 398 | FD0506D6236C4A8F003260B9 /* TopListView.swift in Sources */, 399 | FD794B6D2462D35B00C000CD /* EventDetailMapButtonView.swift in Sources */, 400 | FD0506DC2371282C003260B9 /* SafariView.swift in Sources */, 401 | FD9E6FE62953260500979FFF /* StudyGroupEventFetcherForSwiftUIApp.swift in Sources */, 402 | FD9E6FE029504FE000979FFF /* NewMapView.swift in Sources */, 403 | FD0506D3236C471E003260B9 /* Event.swift in Sources */, 404 | FDA2705C24A7873A009A8505 /* EventLabelView.swift in Sources */, 405 | FD0506DA23712219003260B9 /* EventDetailView.swift in Sources */, 406 | FD525C65237133AE00F9C171 /* StudyGroupEventFetcher.swift in Sources */, 407 | FD50073623AFBEEE00C369EF /* EventDetailPartView.swift in Sources */, 408 | FD9E6FE42952BB3400979FFF /* APIError.swift in Sources */, 409 | ); 410 | runOnlyForDeploymentPostprocessing = 0; 411 | }; 412 | FD9EB149236C33EF00DD6367 /* Sources */ = { 413 | isa = PBXSourcesBuildPhase; 414 | buildActionMask = 2147483647; 415 | files = ( 416 | FD9EB152236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUITests.swift in Sources */, 417 | ); 418 | runOnlyForDeploymentPostprocessing = 0; 419 | }; 420 | FD9EB154236C33EF00DD6367 /* Sources */ = { 421 | isa = PBXSourcesBuildPhase; 422 | buildActionMask = 2147483647; 423 | files = ( 424 | FD9EB15D236C33EF00DD6367 /* StudyGroupEventFetcherForSwiftUIUITests.swift in Sources */, 425 | ); 426 | runOnlyForDeploymentPostprocessing = 0; 427 | }; 428 | /* End PBXSourcesBuildPhase section */ 429 | 430 | /* Begin PBXTargetDependency section */ 431 | FD9EB14F236C33EF00DD6367 /* PBXTargetDependency */ = { 432 | isa = PBXTargetDependency; 433 | target = FD9EB136236C33EE00DD6367 /* StudyGroupEventFetcherForSwiftUI */; 434 | targetProxy = FD9EB14E236C33EF00DD6367 /* PBXContainerItemProxy */; 435 | }; 436 | FD9EB15A236C33EF00DD6367 /* PBXTargetDependency */ = { 437 | isa = PBXTargetDependency; 438 | target = FD9EB136236C33EE00DD6367 /* StudyGroupEventFetcherForSwiftUI */; 439 | targetProxy = FD9EB159236C33EF00DD6367 /* PBXContainerItemProxy */; 440 | }; 441 | /* End PBXTargetDependency section */ 442 | 443 | /* Begin PBXVariantGroup section */ 444 | FD9EB145236C33EF00DD6367 /* LaunchScreen.storyboard */ = { 445 | isa = PBXVariantGroup; 446 | children = ( 447 | FD9EB146236C33EF00DD6367 /* Base */, 448 | ); 449 | name = LaunchScreen.storyboard; 450 | sourceTree = ""; 451 | }; 452 | /* End PBXVariantGroup section */ 453 | 454 | /* Begin XCBuildConfiguration section */ 455 | FD9EB15F236C33EF00DD6367 /* Debug */ = { 456 | isa = XCBuildConfiguration; 457 | buildSettings = { 458 | ALWAYS_SEARCH_USER_PATHS = NO; 459 | CLANG_ANALYZER_NONNULL = YES; 460 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 461 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 462 | CLANG_CXX_LIBRARY = "libc++"; 463 | CLANG_ENABLE_MODULES = YES; 464 | CLANG_ENABLE_OBJC_ARC = YES; 465 | CLANG_ENABLE_OBJC_WEAK = YES; 466 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 467 | CLANG_WARN_BOOL_CONVERSION = YES; 468 | CLANG_WARN_COMMA = YES; 469 | CLANG_WARN_CONSTANT_CONVERSION = YES; 470 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 471 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 472 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 473 | CLANG_WARN_EMPTY_BODY = YES; 474 | CLANG_WARN_ENUM_CONVERSION = YES; 475 | CLANG_WARN_INFINITE_RECURSION = YES; 476 | CLANG_WARN_INT_CONVERSION = YES; 477 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 478 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 479 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 480 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 481 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 482 | CLANG_WARN_STRICT_PROTOTYPES = YES; 483 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 484 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 485 | CLANG_WARN_UNREACHABLE_CODE = YES; 486 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 487 | COPY_PHASE_STRIP = NO; 488 | DEBUG_INFORMATION_FORMAT = dwarf; 489 | ENABLE_STRICT_OBJC_MSGSEND = YES; 490 | ENABLE_TESTABILITY = YES; 491 | GCC_C_LANGUAGE_STANDARD = gnu11; 492 | GCC_DYNAMIC_NO_PIC = NO; 493 | GCC_NO_COMMON_BLOCKS = YES; 494 | GCC_OPTIMIZATION_LEVEL = 0; 495 | GCC_PREPROCESSOR_DEFINITIONS = ( 496 | "DEBUG=1", 497 | "$(inherited)", 498 | ); 499 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 500 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 501 | GCC_WARN_UNDECLARED_SELECTOR = YES; 502 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 503 | GCC_WARN_UNUSED_FUNCTION = YES; 504 | GCC_WARN_UNUSED_VARIABLE = YES; 505 | IPHONEOS_DEPLOYMENT_TARGET = 16.0; 506 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 507 | MTL_FAST_MATH = YES; 508 | ONLY_ACTIVE_ARCH = YES; 509 | SDKROOT = iphoneos; 510 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 511 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 512 | }; 513 | name = Debug; 514 | }; 515 | FD9EB160236C33EF00DD6367 /* Release */ = { 516 | isa = XCBuildConfiguration; 517 | buildSettings = { 518 | ALWAYS_SEARCH_USER_PATHS = NO; 519 | CLANG_ANALYZER_NONNULL = YES; 520 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 521 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 522 | CLANG_CXX_LIBRARY = "libc++"; 523 | CLANG_ENABLE_MODULES = YES; 524 | CLANG_ENABLE_OBJC_ARC = YES; 525 | CLANG_ENABLE_OBJC_WEAK = YES; 526 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 527 | CLANG_WARN_BOOL_CONVERSION = YES; 528 | CLANG_WARN_COMMA = YES; 529 | CLANG_WARN_CONSTANT_CONVERSION = YES; 530 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 531 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 532 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 533 | CLANG_WARN_EMPTY_BODY = YES; 534 | CLANG_WARN_ENUM_CONVERSION = YES; 535 | CLANG_WARN_INFINITE_RECURSION = YES; 536 | CLANG_WARN_INT_CONVERSION = YES; 537 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 538 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 539 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 540 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 541 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 542 | CLANG_WARN_STRICT_PROTOTYPES = YES; 543 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 544 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 545 | CLANG_WARN_UNREACHABLE_CODE = YES; 546 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 547 | COPY_PHASE_STRIP = NO; 548 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 549 | ENABLE_NS_ASSERTIONS = NO; 550 | ENABLE_STRICT_OBJC_MSGSEND = YES; 551 | GCC_C_LANGUAGE_STANDARD = gnu11; 552 | GCC_NO_COMMON_BLOCKS = YES; 553 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 554 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 555 | GCC_WARN_UNDECLARED_SELECTOR = YES; 556 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 557 | GCC_WARN_UNUSED_FUNCTION = YES; 558 | GCC_WARN_UNUSED_VARIABLE = YES; 559 | IPHONEOS_DEPLOYMENT_TARGET = 16.0; 560 | MTL_ENABLE_DEBUG_INFO = NO; 561 | MTL_FAST_MATH = YES; 562 | SDKROOT = iphoneos; 563 | SWIFT_COMPILATION_MODE = wholemodule; 564 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 565 | VALIDATE_PRODUCT = YES; 566 | }; 567 | name = Release; 568 | }; 569 | FD9EB162236C33EF00DD6367 /* Debug */ = { 570 | isa = XCBuildConfiguration; 571 | buildSettings = { 572 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 573 | CODE_SIGN_STYLE = Automatic; 574 | DEVELOPMENT_ASSET_PATHS = "\"StudyGroupEventFetcherForSwiftUI/Preview Content\""; 575 | DEVELOPMENT_TEAM = 7M7ZGYSAKB; 576 | ENABLE_PREVIEWS = YES; 577 | INFOPLIST_FILE = StudyGroupEventFetcherForSwiftUI/Info.plist; 578 | LD_RUNPATH_SEARCH_PATHS = ( 579 | "$(inherited)", 580 | "@executable_path/Frameworks", 581 | ); 582 | MARKETING_VERSION = 1.1.0; 583 | PRODUCT_BUNDLE_IDENTIFIER = com.ASTK.StudyGroupEventFetcherForSwiftUI; 584 | PRODUCT_NAME = "$(TARGET_NAME)"; 585 | SWIFT_VERSION = 5.0; 586 | TARGETED_DEVICE_FAMILY = "1,2"; 587 | }; 588 | name = Debug; 589 | }; 590 | FD9EB163236C33EF00DD6367 /* Release */ = { 591 | isa = XCBuildConfiguration; 592 | buildSettings = { 593 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 594 | CODE_SIGN_STYLE = Automatic; 595 | DEVELOPMENT_ASSET_PATHS = "\"StudyGroupEventFetcherForSwiftUI/Preview Content\""; 596 | DEVELOPMENT_TEAM = 7M7ZGYSAKB; 597 | ENABLE_PREVIEWS = YES; 598 | INFOPLIST_FILE = StudyGroupEventFetcherForSwiftUI/Info.plist; 599 | LD_RUNPATH_SEARCH_PATHS = ( 600 | "$(inherited)", 601 | "@executable_path/Frameworks", 602 | ); 603 | MARKETING_VERSION = 1.1.0; 604 | PRODUCT_BUNDLE_IDENTIFIER = com.ASTK.StudyGroupEventFetcherForSwiftUI; 605 | PRODUCT_NAME = "$(TARGET_NAME)"; 606 | SWIFT_VERSION = 5.0; 607 | TARGETED_DEVICE_FAMILY = "1,2"; 608 | }; 609 | name = Release; 610 | }; 611 | FD9EB165236C33EF00DD6367 /* Debug */ = { 612 | isa = XCBuildConfiguration; 613 | buildSettings = { 614 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 615 | BUNDLE_LOADER = "$(TEST_HOST)"; 616 | CODE_SIGN_STYLE = Automatic; 617 | DEVELOPMENT_TEAM = 7M7ZGYSAKB; 618 | INFOPLIST_FILE = StudyGroupEventFetcherForSwiftUITests/Info.plist; 619 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 620 | LD_RUNPATH_SEARCH_PATHS = ( 621 | "$(inherited)", 622 | "@executable_path/Frameworks", 623 | "@loader_path/Frameworks", 624 | ); 625 | PRODUCT_BUNDLE_IDENTIFIER = com.ASTK.StudyGroupEventFetcherForSwiftUITests; 626 | PRODUCT_NAME = "$(TARGET_NAME)"; 627 | SWIFT_VERSION = 5.0; 628 | TARGETED_DEVICE_FAMILY = "1,2"; 629 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/StudyGroupEventFetcherForSwiftUI.app/StudyGroupEventFetcherForSwiftUI"; 630 | }; 631 | name = Debug; 632 | }; 633 | FD9EB166236C33EF00DD6367 /* Release */ = { 634 | isa = XCBuildConfiguration; 635 | buildSettings = { 636 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 637 | BUNDLE_LOADER = "$(TEST_HOST)"; 638 | CODE_SIGN_STYLE = Automatic; 639 | DEVELOPMENT_TEAM = 7M7ZGYSAKB; 640 | INFOPLIST_FILE = StudyGroupEventFetcherForSwiftUITests/Info.plist; 641 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 642 | LD_RUNPATH_SEARCH_PATHS = ( 643 | "$(inherited)", 644 | "@executable_path/Frameworks", 645 | "@loader_path/Frameworks", 646 | ); 647 | PRODUCT_BUNDLE_IDENTIFIER = com.ASTK.StudyGroupEventFetcherForSwiftUITests; 648 | PRODUCT_NAME = "$(TARGET_NAME)"; 649 | SWIFT_VERSION = 5.0; 650 | TARGETED_DEVICE_FAMILY = "1,2"; 651 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/StudyGroupEventFetcherForSwiftUI.app/StudyGroupEventFetcherForSwiftUI"; 652 | }; 653 | name = Release; 654 | }; 655 | FD9EB168236C33EF00DD6367 /* Debug */ = { 656 | isa = XCBuildConfiguration; 657 | buildSettings = { 658 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 659 | CODE_SIGN_STYLE = Automatic; 660 | DEVELOPMENT_TEAM = 7M7ZGYSAKB; 661 | INFOPLIST_FILE = StudyGroupEventFetcherForSwiftUIUITests/Info.plist; 662 | LD_RUNPATH_SEARCH_PATHS = ( 663 | "$(inherited)", 664 | "@executable_path/Frameworks", 665 | "@loader_path/Frameworks", 666 | ); 667 | PRODUCT_BUNDLE_IDENTIFIER = com.ASTK.StudyGroupEventFetcherForSwiftUIUITests; 668 | PRODUCT_NAME = "$(TARGET_NAME)"; 669 | SWIFT_VERSION = 5.0; 670 | TARGETED_DEVICE_FAMILY = "1,2"; 671 | TEST_TARGET_NAME = StudyGroupEventFetcherForSwiftUI; 672 | }; 673 | name = Debug; 674 | }; 675 | FD9EB169236C33EF00DD6367 /* Release */ = { 676 | isa = XCBuildConfiguration; 677 | buildSettings = { 678 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 679 | CODE_SIGN_STYLE = Automatic; 680 | DEVELOPMENT_TEAM = 7M7ZGYSAKB; 681 | INFOPLIST_FILE = StudyGroupEventFetcherForSwiftUIUITests/Info.plist; 682 | LD_RUNPATH_SEARCH_PATHS = ( 683 | "$(inherited)", 684 | "@executable_path/Frameworks", 685 | "@loader_path/Frameworks", 686 | ); 687 | PRODUCT_BUNDLE_IDENTIFIER = com.ASTK.StudyGroupEventFetcherForSwiftUIUITests; 688 | PRODUCT_NAME = "$(TARGET_NAME)"; 689 | SWIFT_VERSION = 5.0; 690 | TARGETED_DEVICE_FAMILY = "1,2"; 691 | TEST_TARGET_NAME = StudyGroupEventFetcherForSwiftUI; 692 | }; 693 | name = Release; 694 | }; 695 | /* End XCBuildConfiguration section */ 696 | 697 | /* Begin XCConfigurationList section */ 698 | FD9EB132236C33EE00DD6367 /* Build configuration list for PBXProject "StudyGroupEventFetcherForSwiftUI" */ = { 699 | isa = XCConfigurationList; 700 | buildConfigurations = ( 701 | FD9EB15F236C33EF00DD6367 /* Debug */, 702 | FD9EB160236C33EF00DD6367 /* Release */, 703 | ); 704 | defaultConfigurationIsVisible = 0; 705 | defaultConfigurationName = Release; 706 | }; 707 | FD9EB161236C33EF00DD6367 /* Build configuration list for PBXNativeTarget "StudyGroupEventFetcherForSwiftUI" */ = { 708 | isa = XCConfigurationList; 709 | buildConfigurations = ( 710 | FD9EB162236C33EF00DD6367 /* Debug */, 711 | FD9EB163236C33EF00DD6367 /* Release */, 712 | ); 713 | defaultConfigurationIsVisible = 0; 714 | defaultConfigurationName = Release; 715 | }; 716 | FD9EB164236C33EF00DD6367 /* Build configuration list for PBXNativeTarget "StudyGroupEventFetcherForSwiftUITests" */ = { 717 | isa = XCConfigurationList; 718 | buildConfigurations = ( 719 | FD9EB165236C33EF00DD6367 /* Debug */, 720 | FD9EB166236C33EF00DD6367 /* Release */, 721 | ); 722 | defaultConfigurationIsVisible = 0; 723 | defaultConfigurationName = Release; 724 | }; 725 | FD9EB167236C33EF00DD6367 /* Build configuration list for PBXNativeTarget "StudyGroupEventFetcherForSwiftUIUITests" */ = { 726 | isa = XCConfigurationList; 727 | buildConfigurations = ( 728 | FD9EB168236C33EF00DD6367 /* Debug */, 729 | FD9EB169236C33EF00DD6367 /* Release */, 730 | ); 731 | defaultConfigurationIsVisible = 0; 732 | defaultConfigurationName = Release; 733 | }; 734 | /* End XCConfigurationList section */ 735 | }; 736 | rootObject = FD9EB12F236C33EE00DD6367 /* Project object */; 737 | } 738 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI.xcodeproj/xcuserdata/milanista.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | StudyGroupEventFetcherForSwiftUI.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "app_icon40.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "app_icon60.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "app_icon58.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "app_icon87.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "app_icon80.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "app_icon120.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "app_icon120-1.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "app_icon180.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "size" : "20x20", 53 | "idiom" : "ipad", 54 | "filename" : "app_icon20.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "app_icon40-1.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "29x29", 65 | "idiom" : "ipad", 66 | "filename" : "app_icon29.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "app_icon58-1.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "40x40", 77 | "idiom" : "ipad", 78 | "filename" : "app_icon40-2.png", 79 | "scale" : "1x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "app_icon80-1.png", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "size" : "76x76", 89 | "idiom" : "ipad", 90 | "filename" : "app_icon76.png", 91 | "scale" : "1x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "app_icon152.png", 97 | "scale" : "2x" 98 | }, 99 | { 100 | "size" : "83.5x83.5", 101 | "idiom" : "ipad", 102 | "filename" : "app_icon167.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "1024x1024", 107 | "idiom" : "ios-marketing", 108 | "filename" : "app_icon1024.png", 109 | "scale" : "1x" 110 | } 111 | ], 112 | "info" : { 113 | "version" : 1, 114 | "author" : "xcode" 115 | } 116 | } -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon1024.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon120-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon120-1.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon120.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon152.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon167.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon180.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon20.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon29.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon40-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon40-1.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon40-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon40-2.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon40.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon58-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon58-1.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon58.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon60.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon76.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon80-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon80-1.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon80.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/AppIcon.appiconset/app_icon87.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/Detail/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/Detail/img_yumemi_swift.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "img_yumemi_swift.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Assets.xcassets/Detail/img_yumemi_swift.imageset/img_yumemi_swift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MilanistaDev/StudyGroupEventFetcherForSwiftUI/417935cd89d121bbcaae2d2c8138deffe4927b41/StudyGroupEventFetcherForSwiftUI/Assets.xcassets/Detail/img_yumemi_swift.imageset/img_yumemi_swift.png -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | 28 | UILaunchStoryboardName 29 | LaunchScreen 30 | UIRequiredDeviceCapabilities 31 | 32 | armv7 33 | 34 | UISupportedInterfaceOrientations 35 | 36 | UIInterfaceOrientationPortrait 37 | 38 | UISupportedInterfaceOrientations~ipad 39 | 40 | UIInterfaceOrientationPortrait 41 | UIInterfaceOrientationPortraitUpsideDown 42 | UIInterfaceOrientationLandscapeLeft 43 | UIInterfaceOrientationLandscapeRight 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Model/Event.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Event.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2019/11/01. 6 | // Copyright © 2019 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Event: Decodable, Identifiable, Hashable { 12 | var id: Int 13 | var title: String 14 | var subTitle: String 15 | var eventUrl: String 16 | var hashTag: String 17 | var startDate: String 18 | var endDate: String 19 | var place: String 20 | var address: String 21 | var lat: String? 22 | var lon: String? 23 | var ownerDisplayName: String 24 | 25 | enum CodingKeys: String, CodingKey { 26 | case id = "event_id" 27 | case title = "title" 28 | case subTitle = "catch" 29 | case eventUrl = "event_url" 30 | case hashTag = "hash_tag" 31 | case startDate = "started_at" 32 | case endDate = "ended_at" 33 | case place = "place" 34 | case address = "address" 35 | case lat = "lat" 36 | case lon = "lon" 37 | case ownerDisplayName = "owner_display_name" 38 | } 39 | } 40 | 41 | // Reference of API 42 | // Event Search API 43 | // https://connpass.com/about/api/ 44 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Model/PinItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PinItem.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2022/12/19. 6 | // Copyright © 2022 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import MapKit 11 | 12 | struct PinItem: Identifiable { 13 | let id = UUID() 14 | let coordinate: CLLocationCoordinate2D 15 | } 16 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Model/StudyGroup.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StudyGroup.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2019/11/01. 6 | // Copyright © 2019 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct StudyGroup: Decodable { 12 | var events: [Event] 13 | } 14 | 15 | // Reference of API 16 | // Event Search API 17 | // https://connpass.com/about/api/ 18 | 19 | // Sample mock data 20 | let mockEventsData: [Event] 21 | = [Event(id: 1, 22 | title: "YUMEMI.swift #1 ~WWDC19報告会~", 23 | subTitle: "サブタイトル(キャッチ)", 24 | eventUrl: "https://yumemi.connpass.com/event/131175/", 25 | hashTag: "yumemi_swift", 26 | startDate: "2019-06-24T19:00:00+09:00", 27 | endDate: "2019-06-24T21:30:00+09:00", 28 | place: "株式会社ゆめみ", 29 | address: "東京都世田谷区", 30 | lat: "35.641587300000", 31 | lon: "139.669071500000", 32 | ownerDisplayName: "株式会社ゆめみ"), 33 | Event(id: 2, 34 | title: "YUMEMI.swift #1 ~WWDC19報告会~ パプリックビューイング @Sapporo", 35 | subTitle: "サブタイトル(キャッチ)", 36 | eventUrl: "https://yumemi.connpass.com/event/135183/", 37 | hashTag: "yumemi_swift", 38 | startDate: "2019-06-24T19:00:00+09:00", 39 | endDate: "2019-06-24T21:30:00+09:00", 40 | place: "株式会社ゆめみ", 41 | address: "北海道札幌市中央区", 42 | lat: "35.641587300000", 43 | lon: "139.669071500000", 44 | ownerDisplayName: "株式会社ゆめみ"), 45 | Event(id: 3, 46 | title: "Enjoy SwiftUI vol1", 47 | subTitle: "サブタイトル(キャッチ)", 48 | eventUrl: "https://yumemi.connpass.com/event/139079/", 49 | hashTag: "yumemi_swift", 50 | startDate: "2019-07-31T19:00:00+09:00", 51 | endDate: "2019-07-31T21:30:00+09:00", 52 | place: "株式会社ゆめみ", 53 | address: "東京都世田谷区", 54 | lat: "35.641587300000", 55 | lon: "139.669071500000", 56 | ownerDisplayName: "株式会社ゆめみ"), 57 | Event(id: 4, 58 | title: "YUMEMI.swift #3 ~俺/私がやったiOS 13対応~", 59 | subTitle: "サブタイトル(キャッチ)", 60 | eventUrl: "https://yumemi.connpass.com/event/142608/", 61 | hashTag: "yumemi_swift", 62 | startDate: "2019-09-30T19:00:00+09:00", 63 | endDate: "2019-09-30T21:30:00+09:00", 64 | place: "株式会社ゆめみ", 65 | address: "東京都世田谷区", 66 | lat: "35.641587300000", 67 | lon: "139.669071500000", 68 | ownerDisplayName: "株式会社ゆめみ"), 69 | Event(id: 5, 70 | title: "Enjoy SwiftUI vol2", 71 | subTitle: "サブタイトル(キャッチ)", 72 | eventUrl: "https://yumemi.connpass.com/event/151594/", 73 | hashTag: "yumemi_swiftui", 74 | startDate: "2019-11-08T19:00:00+09:00", 75 | endDate: "2019-11-08T21:30:00+09:00", 76 | place: "株式会社ゆめみ", 77 | address: "東京都世田谷区", 78 | lat: "35.641587300000", 79 | lon: "139.669071500000", 80 | ownerDisplayName: "株式会社ゆめみ"), 81 | Event(id: 6, 82 | title: "YUMEMI.swift #5", 83 | subTitle: "サブタイトル(キャッチ)", 84 | eventUrl: "", 85 | hashTag: "yumemi_swift", 86 | startDate: "2019-11-29T19:30:00+09:00", 87 | endDate: "2019-11-29T21:30:00+09:00", 88 | place: "株式会社ゆめみ", 89 | address: "東京都世田谷区", 90 | lat: "35.641587300000", 91 | lon: "139.669071500000", 92 | ownerDisplayName: "株式会社ゆめみ") 93 | ] 94 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Other/APIError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // APIError.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2022/12/21. 6 | // Copyright © 2022 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum APIError: Error { 12 | case network 13 | case response 14 | case jsonDecode 15 | case statusCode(statusCode: String) 16 | } 17 | 18 | extension APIError: LocalizedError { 19 | var errorDescription: String? { 20 | switch self { 21 | case .network: 22 | return "Network Error" 23 | 24 | case .response: 25 | return "Response Error" 26 | 27 | case .jsonDecode: 28 | return "json convert failed in JSONDecoder" 29 | 30 | case .statusCode(let statusCode): 31 | return "Error! StatuCode: " + String(statusCode) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Other/StudyGroupDateFormatter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StudyGroupDateFormatter.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2019/11/05. 6 | // Copyright © 2019 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class StudyGroupDateFormatter: DateFormatter { 12 | 13 | class func convertNormalDateString(dateStr: String, isOnlyDate: Bool) -> String { 14 | let formatter = ISO8601DateFormatter() 15 | let date = formatter.date(from: dateStr) 16 | return convertDateToString(date: date!, isOnlyDate: isOnlyDate) 17 | } 18 | 19 | class func convertDateToString(date: Date, isOnlyDate: Bool) -> String { 20 | let formatter = DateFormatter() 21 | formatter.dateStyle = isOnlyDate ? .none: .short 22 | formatter.timeStyle = .short 23 | formatter.locale = Locale(identifier: "ja_JP") 24 | return formatter.string(from: date) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Other/StudyGroupEventFetcher.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StudyGroupEventFetcher.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2019/11/05. 6 | // Copyright © 2019 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class StudyGroupEventFetcher { 12 | 13 | // connpass's event search API 14 | private let urlLink = "https://connpass.com/api/v1/event/?keyword=YUMEMI.swift&count=100" 15 | 16 | func fetchEventData() async throws -> [Event] { 17 | let (data, response) = try await URLSession.shared.data(from: URL(string: urlLink)!) 18 | 19 | guard let httpResponse = response as? HTTPURLResponse else { 20 | throw APIError.response 21 | } 22 | 23 | switch httpResponse.statusCode { 24 | case 200: 25 | do { 26 | let searchedResultData = try JSONDecoder().decode(StudyGroup.self, from: data) 27 | return searchedResultData.events.reversed() 28 | 29 | } catch { 30 | throw APIError.jsonDecode 31 | } 32 | 33 | default: 34 | throw APIError.statusCode(statusCode: httpResponse.statusCode.description) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/StudyGroupEventFetcherForSwiftUIApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StudyGroupEventFetcherForSwiftUIApp.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2022/12/21. 6 | // Copyright © 2022 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | @main 12 | struct StudyGroupEventFetcherForSwiftUIApp: App { 13 | var body: some Scene { 14 | WindowGroup { 15 | TopListView() 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/ViewModel/TopListViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TopListViewModel.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2019/11/05. 6 | // Copyright © 2019 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class TopListViewModel: ObservableObject { 12 | @Published var eventData: [Event] = [] 13 | @Published var isShowIndicator = false 14 | @Published var error: APIError? 15 | @Published var isShowAlert = false 16 | 17 | private let fetcher = StudyGroupEventFetcher() 18 | 19 | /// 勉強会データをAPIを叩いて取得(async/await版) 20 | func fetchEventData() { 21 | Task { @MainActor in 22 | isShowIndicator = true 23 | defer { 24 | isShowIndicator = false 25 | } 26 | try? await Task.sleep(nanoseconds: 1_000_000_000) 27 | 28 | do { 29 | eventData = try await fetcher.fetchEventData() 30 | 31 | } catch { 32 | if let apiError = error as? APIError { 33 | self.error = apiError 34 | isShowAlert = true 35 | } else if let error = error as? URLError, error.code == URLError.notConnectedToInternet { 36 | self.error = APIError.network 37 | isShowAlert = true 38 | } else { 39 | // 🤔 40 | print(error.localizedDescription) 41 | } 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Views/Common/LoadingView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoadingView.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2020/07/02. 6 | // Copyright © 2020 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct LoadingView: View { 12 | var body: some View { 13 | ZStack { 14 | RoundedRectangle(cornerRadius: 10.0) 15 | .fill(Color.gray) 16 | .frame(width: 100.0, height: 100.0, alignment: .center) 17 | VStack { 18 | Text("💫") 19 | .padding(.bottom, 10.0) 20 | .font(.title) 21 | Text("Loading...") 22 | .font(.body) 23 | .bold() 24 | .foregroundColor(.white) 25 | } 26 | } 27 | } 28 | } 29 | struct LoadingView_Previews: PreviewProvider { 30 | static var previews: some View { 31 | LoadingView() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Views/Common/LoadingViewModifier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoadingViewModifier.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2022/12/17. 6 | // Copyright © 2022 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | /// ローディング画面を出すViewModifier 12 | struct LoadingViewModifier: ViewModifier { 13 | var isRefreshing: Bool 14 | 15 | func body(content: Content) -> some View { 16 | ZStack { 17 | content 18 | .allowsHitTesting(!isRefreshing) 19 | 20 | if isRefreshing { 21 | ProgressView { 22 | Text("Loading...") 23 | } 24 | } 25 | } 26 | } 27 | } 28 | 29 | extension View { 30 | /// 通信中にProgressViewを表示 31 | /// - Parameters: 32 | /// - isRefreshing: 通信中か 33 | /// - Returns: ローディング画面 34 | func loading(isRefreshing: Bool, safeAreaEdges: Edge.Set = []) -> some View { 35 | modifier(LoadingViewModifier(isRefreshing: isRefreshing)) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Views/EventDetail/EventDetailButtonView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EventDetailButtonView.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by 麻生 拓弥 on 2020/04/18. 6 | // Copyright © 2020 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct EventDetailButtonView: View { 12 | 13 | let eventUrl: String 14 | 15 | var body: some View { 16 | if #available(iOS 14.0, *) { 17 | return AnyView(EventLinkView(eventUrl: self.eventUrl)) 18 | } else { 19 | return AnyView(EventLinkButton(eventUrl: self.eventUrl)) 20 | } 21 | } 22 | } 23 | 24 | /// iOS 14 で Link を使って Safari を開くボタン 25 | @available(iOS 14.0, *) 26 | struct EventLinkView: View { 27 | var eventUrl: String 28 | var body: some View { 29 | Link(destination: URL(string: self.eventUrl)!) { 30 | EventDetailButtonTitleView() 31 | }.padding(20.0) 32 | } 33 | } 34 | 35 | /// iOS 13 で SafariVC を開くボタン 36 | struct EventLinkButton: View { 37 | var eventUrl: String 38 | @State private var showModal = false 39 | var body: some View { 40 | Button(action: { 41 | self.showModal.toggle() 42 | }) { 43 | EventDetailButtonTitleView() 44 | } 45 | .sheet(isPresented: $showModal) { 46 | SafariView(url: URL(string: self.eventUrl)) 47 | .edgesIgnoringSafeArea(.bottom) 48 | }.padding(20.0) 49 | } 50 | } 51 | 52 | struct EventDetailButtonTitleView: View { 53 | var body: some View { 54 | Text("connpassのイベントページ") 55 | .frame(minWidth: 0, maxWidth: .infinity) 56 | .padding() 57 | .font(Font.body.bold()) 58 | .foregroundColor(.white) 59 | .background(Color.red) 60 | .cornerRadius(5.0) 61 | } 62 | } 63 | struct EventDetailButtonView_Previews: PreviewProvider { 64 | static var previews: some View { 65 | EventDetailButtonView(eventUrl: mockEventsData[0].eventUrl) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Views/EventDetail/EventDetailMapButtonView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EventDetailMapButtonView.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2020/05/06. 6 | // Copyright © 2020 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct EventDetailMapButtonView: View { 12 | 13 | @Binding var zoomValue: Double 14 | 15 | var body: some View { 16 | VStack { 17 | Button(action: { 18 | // マップ拡大 19 | self.zoomValue *= 0.5 20 | }) { 21 | Image(systemName: "plus.app.fill") 22 | .resizable() 23 | .frame(width: 30.0, height: 30.0) 24 | .foregroundColor(.gray) 25 | } 26 | Button(action: { 27 | // マップ縮小 28 | self.zoomValue *= 2 29 | }) { 30 | Image(systemName: "minus.square.fill") 31 | .resizable() 32 | .frame(width: 30.0, height: 30.0) 33 | .foregroundColor(.gray) 34 | } 35 | } 36 | } 37 | } 38 | 39 | struct EventDetailMapButtonView_Previews: PreviewProvider { 40 | static var previews: some View { 41 | EventDetailMapButtonView(zoomValue: .constant(0.01)) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Views/EventDetail/EventDetailPartView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EventDetailPartView.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2019/12/23. 6 | // Copyright © 2019 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct EventDetailPartView: View { 12 | // Event Model 13 | let eventData: Event 14 | 15 | var body: some View { 16 | VStack(alignment: .leading) { 17 | Text(eventData.title) 18 | .font(.headline) 19 | .lineLimit(2) 20 | .fixedSize(horizontal: false, vertical: true) 21 | .padding(.vertical, 8.0) 22 | Text(eventData.subTitle) 23 | .font(.caption) 24 | .foregroundColor(.gray) 25 | .lineLimit(3) 26 | .fixedSize(horizontal: false, vertical: true) 27 | .padding(.bottom, 24.0) 28 | Text(eventData.place) 29 | .font(.headline) 30 | .lineLimit(2) 31 | .fixedSize(horizontal: false, vertical: true) 32 | .padding(.bottom, 12.0) 33 | Text(eventData.address) 34 | .font(.footnote) 35 | .lineLimit(2) 36 | .fixedSize(horizontal: false, vertical: true) 37 | .padding(.bottom, 24.0) 38 | Text(StudyGroupDateFormatter.convertNormalDateString(dateStr: eventData.startDate, isOnlyDate: false) + " ~ " + StudyGroupDateFormatter.convertNormalDateString(dateStr: eventData.endDate, isOnlyDate: true)) 39 | .font(.subheadline) 40 | .padding(.bottom, 48.0) 41 | } 42 | .padding(.horizontal, 20.0) 43 | } 44 | } 45 | 46 | struct EventDetailPartView_Previews: PreviewProvider { 47 | static var previews: some View { 48 | EventDetailPartView(eventData: mockEventsData[0]) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Views/EventDetail/EventDetailView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EventDetailView.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2019/11/05. 6 | // Copyright © 2019 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct EventDetailView: View { 12 | let eventData: Event // From ListView(静的モデル) 13 | @State private var zoomValue = 0.01 14 | 15 | var body: some View { 16 | ScrollView { 17 | VStack(alignment: .leading) { 18 | // MapView Part 19 | ZStack(alignment: .bottomTrailing) { 20 | NewMapView( 21 | eventData: eventData, 22 | zoomValue: $zoomValue 23 | ) 24 | .frame(height: 300.0) 25 | 26 | EventDetailMapButtonView(zoomValue: $zoomValue) 27 | .padding(.bottom, 24.0) 28 | .padding(.trailing, 12.0) 29 | } 30 | // Event detail part 31 | EventDetailPartView(eventData: self.eventData) 32 | // Bottom button 33 | EventDetailButtonView(eventUrl: self.eventData.eventUrl) 34 | } 35 | } 36 | .navigationTitle("勉強会詳細") 37 | .navigationBarTitleDisplayMode(.inline) 38 | } 39 | } 40 | 41 | struct EventDetailView_Previews: PreviewProvider { 42 | static var previews: some View { 43 | EventDetailView(eventData: mockEventsData[0]) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Views/Map/NewMapView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewMapView.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2022/12/19. 6 | // Copyright © 2022 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | import MapKit 11 | 12 | struct NewMapView: View { 13 | // リスト画面から渡ってくる勉強会情報 14 | let eventData: Event 15 | // 詳細画面のマップの右下の+ - ボタンで変わるズームの値 16 | @Binding var zoomValue: CLLocationDegrees 17 | 18 | @State private var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 35.6816005869028, longitude: 139.76595878344898), span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01)) 19 | 20 | var body: some View { 21 | Map( 22 | coordinateRegion: $region, 23 | annotationItems: generatePinItem()) { item in 24 | MapMarker(coordinate: item.coordinate) 25 | } 26 | .onAppear { 27 | setTargetRegion() 28 | } 29 | .onChange(of: zoomValue) { newValue in 30 | // + - ボタンでズームの値が変わるのでその変化を検知してマップの拡大縮小を行う 31 | region.span = MKCoordinateSpan(latitudeDelta: zoomValue, longitudeDelta: zoomValue) 32 | } 33 | } 34 | } 35 | 36 | extension NewMapView { 37 | /// アノテーション用のデータを生成 38 | private func generatePinItem() -> [PinItem] { 39 | guard let latitude = eventData.lat, 40 | let latValue = Double(latitude), 41 | let longitude = eventData.lon, 42 | let lonValue = Double(longitude) else { 43 | return [] 44 | } 45 | return [PinItem(coordinate: CLLocationCoordinate2D(latitude: latValue, longitude: lonValue))] 46 | } 47 | 48 | /// 表示時にマップの中央を会場の場所にする 49 | private func setTargetRegion() { 50 | guard let latitude = eventData.lat, 51 | let latValue = Double(latitude), 52 | let longitude = eventData.lon, 53 | let lonValue = Double(longitude) else { 54 | // オンライン開催などで緯度経度の情報がnilの場合広域にしておく 55 | region.span = MKCoordinateSpan(latitudeDelta: 30, longitudeDelta: 30) 56 | return 57 | } 58 | // マップの中央を会場に 59 | region.center = CLLocationCoordinate2D(latitude: latValue, longitude: lonValue) 60 | } 61 | } 62 | 63 | struct NewMapView_Previews: PreviewProvider { 64 | static var previews: some View { 65 | NewMapView(eventData: mockEventsData[0], zoomValue: .constant(0.01)) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Views/Safari/SafariView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SafariView.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2019/11/05. 6 | // Copyright © 2019 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | import SafariServices 11 | 12 | struct SafariView: UIViewControllerRepresentable { 13 | typealias UIViewControllerType = SFSafariViewController 14 | 15 | var url: URL? 16 | 17 | func makeUIViewController(context: UIViewControllerRepresentableContext) -> SFSafariViewController { 18 | return SFSafariViewController(url: url!) 19 | } 20 | 21 | func updateUIViewController(_ safariViewController: SFSafariViewController, context: UIViewControllerRepresentableContext) { 22 | } 23 | } 24 | 25 | struct SafariView_Previews: PreviewProvider { 26 | static var previews: some View { 27 | SafariView(url: URL(string: mockEventsData[0].eventUrl)!) 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Views/TopEventList/EventLabelView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EventLabelView.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2020/06/27. 6 | // Copyright © 2020 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | enum ColorType { 12 | case multiColor 13 | case monochrome 14 | } 15 | 16 | struct EventLabelView: View { 17 | 18 | let labelName: String 19 | let iconName: String 20 | let colorType: ColorType 21 | 22 | var body: some View { 23 | HStack { 24 | switch colorType { 25 | case .monochrome: 26 | Image(systemName: iconName) 27 | .imageScale(.medium) 28 | .foregroundColor(.red) 29 | case .multiColor: 30 | if #available(iOS 14.0, *) { 31 | Image(systemName: iconName) 32 | .renderingMode(.original) 33 | .imageScale(.medium) 34 | } else { 35 | Image(systemName: iconName) 36 | .imageScale(.medium) 37 | .foregroundColor(.red) 38 | } 39 | } 40 | Text(labelName) 41 | .font(.footnote) 42 | .lineLimit(3) 43 | .fixedSize(horizontal: false, vertical: true) 44 | }.padding(.bottom, 6.0) 45 | } 46 | } 47 | 48 | struct EventLabelView_Previews: PreviewProvider { 49 | static var previews: some View { 50 | EventLabelView(labelName: mockEventsData[0].address, 51 | iconName: "mappin.circle.fill", 52 | colorType: .multiColor) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Views/TopEventList/EventRowView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EventRowView.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2019/11/01. 6 | // Copyright © 2019 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct EventRowView: View { 12 | 13 | let eventData: Event 14 | 15 | var body: some View { 16 | VStack(alignment: .leading) { 17 | Text(eventData.title) 18 | .bold() 19 | .font(.headline) 20 | .lineLimit(2) 21 | .fixedSize(horizontal: false, vertical: true) 22 | .padding(.vertical, 8.0) 23 | EventLabelView( 24 | labelName: StudyGroupDateFormatter.convertNormalDateString(dateStr: eventData.startDate, isOnlyDate: false) + "~", 25 | iconName: "calendar.circle.fill", 26 | colorType: .multiColor) 27 | EventLabelView(labelName: eventData.ownerDisplayName + " 他", 28 | iconName: "person.fill", 29 | colorType: .monochrome) 30 | EventLabelView(labelName: eventData.address, 31 | iconName: "mappin.circle.fill", 32 | colorType: .multiColor) 33 | HStack { 34 | Spacer() 35 | Text("#" + eventData.hashTag) 36 | .foregroundColor(.blue) 37 | .font(.caption) 38 | .bold() 39 | .padding(.horizontal, 8.0) 40 | .padding(.vertical, 4.0) 41 | .overlay( 42 | RoundedRectangle(cornerRadius: 20.0) 43 | .stroke(Color.blue, lineWidth: 1.0) 44 | ) 45 | } 46 | .padding(.bottom, 8.0) 47 | } 48 | } 49 | } 50 | 51 | struct EventRowView_Previews: PreviewProvider { 52 | static var previews: some View { 53 | EventRowView(eventData: mockEventsData[0]) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUI/Views/TopEventList/TopListView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TopListView.swift 3 | // StudyGroupEventFetcherForSwiftUI 4 | // 5 | // Created by Takuya Aso on 2019/11/01. 6 | // Copyright © 2019 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct TopListView: View { 12 | @StateObject private var topListVM = TopListViewModel() 13 | 14 | var body: some View { 15 | NavigationStack { 16 | List(topListVM.eventData) { event in 17 | NavigationLink(value: event) { 18 | EventRowView(eventData: event) 19 | } 20 | } 21 | .navigationDestination(for: Event.self) { event in 22 | EventDetailView(eventData: event) 23 | } 24 | .navigationTitle("YUMEMI.swift一覧") 25 | .navigationBarTitleDisplayMode(.large) 26 | .loading(isRefreshing: topListVM.isShowIndicator) 27 | } 28 | .onAppear { 29 | topListVM.fetchEventData() 30 | } 31 | .alert(isPresented: $topListVM.isShowAlert, error: topListVM.error) { _ in 32 | Button("OK", action: {}) 33 | } message: { error in 34 | Text(error.errorDescription ?? "なぜかnilみたいね") 35 | } 36 | } 37 | } 38 | 39 | struct TopListView_Previews: PreviewProvider { 40 | static var previews: some View { 41 | TopListView() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUITests/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUITests/StudyGroupEventFetcherForSwiftUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StudyGroupEventFetcherForSwiftUITests.swift 3 | // StudyGroupEventFetcherForSwiftUITests 4 | // 5 | // Created by Takuya Aso on 2019/11/01. 6 | // Copyright © 2019 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import StudyGroupEventFetcherForSwiftUI 11 | 12 | class StudyGroupEventFetcherForSwiftUITests: XCTestCase { 13 | 14 | override func setUp() { 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | } 21 | 22 | func testExample() { 23 | // This is an example of a functional test case. 24 | // Use XCTAssert and related functions to verify your tests produce the correct results. 25 | } 26 | 27 | func testPerformanceExample() { 28 | // This is an example of a performance test case. 29 | self.measure { 30 | // Put the code you want to measure the time of here. 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUIUITests/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /StudyGroupEventFetcherForSwiftUIUITests/StudyGroupEventFetcherForSwiftUIUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StudyGroupEventFetcherForSwiftUIUITests.swift 3 | // StudyGroupEventFetcherForSwiftUIUITests 4 | // 5 | // Created by Takuya Aso on 2019/11/01. 6 | // Copyright © 2019 Takuya Aso. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class StudyGroupEventFetcherForSwiftUIUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | 16 | // In UI tests it is usually best to stop immediately when a failure occurs. 17 | continueAfterFailure = false 18 | 19 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 20 | } 21 | 22 | override func tearDown() { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | } 25 | 26 | func testExample() { 27 | // UI tests must launch the application that they test. 28 | let app = XCUIApplication() 29 | app.launch() 30 | 31 | // Use recording to get started writing UI tests. 32 | // Use XCTAssert and related functions to verify your tests produce the correct results. 33 | } 34 | 35 | func testLaunchPerformance() { 36 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { 37 | // This measures how long it takes to launch your application. 38 | measure(metrics: [XCTOSSignpostMetric.applicationLaunch]) { 39 | XCUIApplication().launch() 40 | } 41 | } 42 | } 43 | } 44 | --------------------------------------------------------------------------------