├── skydiving weather ├── Assets.xcassets │ ├── Contents.json │ ├── Theme │ │ ├── Contents.json │ │ ├── sky.colorset │ │ │ └── Contents.json │ │ ├── lightgray.colorset │ │ │ └── Contents.json │ │ ├── mediumorange.colorset │ │ │ └── Contents.json │ │ ├── okgreen.colorset │ │ │ └── Contents.json │ │ └── impossiblered.colorset │ │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── Logo.png │ │ └── Contents.json │ ├── AccentColor.colorset │ │ └── Contents.json │ └── skydiving-homepage.imageset │ │ ├── 236948223_4160534673982793_2172351443596800991_n.jpg │ │ └── Contents.json ├── Preview Content │ └── Preview Assets.xcassets │ │ ├── Contents.json │ │ ├── Figma │ │ ├── Contents.json │ │ ├── Home Page.imageset │ │ │ ├── Screenshot 2022-12-22 at 18.29.59.png │ │ │ └── Contents.json │ │ ├── Result key info Page.imageset │ │ │ ├── Screenshot 2022-12-22 at 18.30.24.png │ │ │ └── Contents.json │ │ └── Result description Page.imageset │ │ │ ├── Screenshot 2022-12-22 at 18.30.12.png │ │ │ └── Contents.json │ │ └── Final result │ │ ├── Contents.json │ │ ├── Autocomplete.imageset │ │ ├── Simulator Screen Shot - iPhone 14 Pro - 2023-01-02 at 23.25.44.png │ │ └── Contents.json │ │ ├── Finished Home Page.imageset │ │ ├── Simulator Screen Shot - iPhone 14 Pro - 2023-01-02 at 23.25.21.png │ │ └── Contents.json │ │ ├── Finished key info page.imageset │ │ ├── Simulator Screen Shot - iPhone 14 Pro - 2023-01-04 at 08.45.21.png │ │ └── Contents.json │ │ └── Finished result description page.imageset │ │ ├── Simulator Screen Shot - iPhone 14 Pro - 2023-01-04 at 08.45.08.png │ │ └── Contents.json ├── skydiving_weatherApp.swift ├── Style │ ├── StyledTextfield.swift │ ├── StyledLabel.swift │ └── ButtonIcon.swift ├── Views │ ├── Subviews │ │ ├── DescriptionView.swift │ │ ├── DayView.swift │ │ ├── DropzoneAutocompleteView.swift │ │ ├── LocalisationView.swift │ │ └── KeyMetricsView.swift │ ├── WeatherResultView.swift │ └── HomePageView.swift ├── Models │ ├── OpenWeatherData.swift │ ├── WeatherInfoByDayModel.swift │ ├── WeatherViewModel.swift │ └── DropZone.swift └── Services │ └── WeatherService.swift ├── skydiving weather.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── xcuserdata │ └── lealescure.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── xcshareddata │ └── xcschemes │ │ └── skydiving weather.xcscheme └── project.pbxproj ├── skydiving-weather-Info.plist ├── README.md └── .gitignore /skydiving weather/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /skydiving weather/Assets.xcassets/Theme/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /skydiving weather/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /skydiving weather/Preview Content/Preview Assets.xcassets/Figma/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /skydiving weather/Preview Content/Preview Assets.xcassets/Final result/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /skydiving weather/Assets.xcassets/AppIcon.appiconset/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llescure/skydiving-app/main/skydiving weather/Assets.xcassets/AppIcon.appiconset/Logo.png -------------------------------------------------------------------------------- /skydiving weather.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /skydiving weather/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 | -------------------------------------------------------------------------------- /skydiving weather/Assets.xcassets/skydiving-homepage.imageset/236948223_4160534673982793_2172351443596800991_n.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llescure/skydiving-app/main/skydiving weather/Assets.xcassets/skydiving-homepage.imageset/236948223_4160534673982793_2172351443596800991_n.jpg -------------------------------------------------------------------------------- /skydiving weather/Preview Content/Preview Assets.xcassets/Figma/Home Page.imageset/Screenshot 2022-12-22 at 18.29.59.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llescure/skydiving-app/main/skydiving weather/Preview Content/Preview Assets.xcassets/Figma/Home Page.imageset/Screenshot 2022-12-22 at 18.29.59.png -------------------------------------------------------------------------------- /skydiving weather/Preview Content/Preview Assets.xcassets/Figma/Result key info Page.imageset/Screenshot 2022-12-22 at 18.30.24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llescure/skydiving-app/main/skydiving weather/Preview Content/Preview Assets.xcassets/Figma/Result key info Page.imageset/Screenshot 2022-12-22 at 18.30.24.png -------------------------------------------------------------------------------- /skydiving weather/Preview Content/Preview Assets.xcassets/Figma/Result description Page.imageset/Screenshot 2022-12-22 at 18.30.12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llescure/skydiving-app/main/skydiving weather/Preview Content/Preview Assets.xcassets/Figma/Result description Page.imageset/Screenshot 2022-12-22 at 18.30.12.png -------------------------------------------------------------------------------- /skydiving weather.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /skydiving weather/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Logo.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | } 9 | ], 10 | "info" : { 11 | "author" : "xcode", 12 | "version" : 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /skydiving weather.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /skydiving weather/Preview Content/Preview Assets.xcassets/Final result/Autocomplete.imageset/Simulator Screen Shot - iPhone 14 Pro - 2023-01-02 at 23.25.44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llescure/skydiving-app/main/skydiving weather/Preview Content/Preview Assets.xcassets/Final result/Autocomplete.imageset/Simulator Screen Shot - iPhone 14 Pro - 2023-01-02 at 23.25.44.png -------------------------------------------------------------------------------- /skydiving weather/Preview Content/Preview Assets.xcassets/Final result/Finished Home Page.imageset/Simulator Screen Shot - iPhone 14 Pro - 2023-01-02 at 23.25.21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llescure/skydiving-app/main/skydiving weather/Preview Content/Preview Assets.xcassets/Final result/Finished Home Page.imageset/Simulator Screen Shot - iPhone 14 Pro - 2023-01-02 at 23.25.21.png -------------------------------------------------------------------------------- /skydiving weather/skydiving_weatherApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // skydiving_weatherApp.swift 3 | // skydiving weather 4 | // 5 | // Created by Léa Lescure on 22/12/2022. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct skydiving_weatherApp: App { 12 | var body: some Scene { 13 | WindowGroup { 14 | HomePageView() 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /skydiving weather/Preview Content/Preview Assets.xcassets/Final result/Finished key info page.imageset/Simulator Screen Shot - iPhone 14 Pro - 2023-01-04 at 08.45.21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llescure/skydiving-app/main/skydiving weather/Preview Content/Preview Assets.xcassets/Final result/Finished key info page.imageset/Simulator Screen Shot - iPhone 14 Pro - 2023-01-04 at 08.45.21.png -------------------------------------------------------------------------------- /skydiving weather/Preview Content/Preview Assets.xcassets/Final result/Finished result description page.imageset/Simulator Screen Shot - iPhone 14 Pro - 2023-01-04 at 08.45.08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llescure/skydiving-app/main/skydiving weather/Preview Content/Preview Assets.xcassets/Final result/Finished result description page.imageset/Simulator Screen Shot - iPhone 14 Pro - 2023-01-04 at 08.45.08.png -------------------------------------------------------------------------------- /skydiving-weather-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIApplicationSceneManifest 6 | 7 | UIApplicationSupportsMultipleScenes 8 | 9 | UISceneConfigurations 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /skydiving weather/Style/StyledTextfield.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StyledTextfield.swift 3 | // skydiving weather 4 | // 5 | // Created by Léa Lescure on 23/12/2022. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | 11 | extension View { 12 | func styledTextfield() -> some View { 13 | self 14 | .overlay(Rectangle().frame(height: 2).padding(.top, 35)) 15 | .foregroundColor(Color("lightgray")) 16 | .disableAutocorrection(true) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /skydiving weather/Assets.xcassets/skydiving-homepage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "236948223_4160534673982793_2172351443596800991_n.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /skydiving weather/Preview Content/Preview Assets.xcassets/Figma/Home Page.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Screenshot 2022-12-22 at 18.29.59.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /skydiving weather/Preview Content/Preview Assets.xcassets/Figma/Result description Page.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Screenshot 2022-12-22 at 18.30.12.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /skydiving weather/Preview Content/Preview Assets.xcassets/Figma/Result key info Page.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Screenshot 2022-12-22 at 18.30.24.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /skydiving weather/Style/StyledLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StyledLabel.swift 3 | // skydiving weather 4 | // 5 | // Created by Léa Lescure on 04/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct StyledLabel: LabelStyle { 11 | func makeBody(configuration: Configuration) -> some View { 12 | HStack (spacing: 10){ 13 | configuration.icon 14 | configuration.title 15 | } 16 | } 17 | } 18 | 19 | extension LabelStyle where Self == StyledLabel { 20 | static var styledLabel: Self { Self() } 21 | } 22 | -------------------------------------------------------------------------------- /skydiving weather/Style/ButtonIcon.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ButtonIcon.swift 3 | // skydiving weather 4 | // 5 | // Created by Léa Lescure on 23/12/2022. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ButtonIconLabelStyle: LabelStyle { 11 | func makeBody(configuration: Configuration) -> some View { 12 | HStack { 13 | configuration.title 14 | configuration.icon 15 | } 16 | } 17 | } 18 | 19 | extension LabelStyle where Self == ButtonIconLabelStyle { 20 | static var buttonIcon: Self { Self() } 21 | } 22 | -------------------------------------------------------------------------------- /skydiving weather/Preview Content/Preview Assets.xcassets/Final result/Autocomplete.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Simulator Screen Shot - iPhone 14 Pro - 2023-01-02 at 23.25.44.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /skydiving weather/Preview Content/Preview Assets.xcassets/Final result/Finished Home Page.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Simulator Screen Shot - iPhone 14 Pro - 2023-01-02 at 23.25.21.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /skydiving weather/Preview Content/Preview Assets.xcassets/Final result/Finished key info page.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Simulator Screen Shot - iPhone 14 Pro - 2023-01-04 at 08.45.21.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /skydiving weather/Preview Content/Preview Assets.xcassets/Final result/Finished result description page.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Simulator Screen Shot - iPhone 14 Pro - 2023-01-04 at 08.45.08.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /skydiving weather.xcodeproj/xcuserdata/lealescure.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | skydiving weather.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | DBE841FC2954CB58005D7F70 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /skydiving weather/Views/Subviews/DescriptionView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DescriptionView.swift 3 | // skydiving weather 4 | // 5 | // Created by Léa Lescure on 03/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct DescriptionView: View { 11 | let dayInfo: WeatherInfoByDay 12 | 13 | var body: some View { 14 | VStack (alignment: .leading, spacing: 10){ 15 | Text("\(dayInfo.description)") 16 | .font(.subheadline) 17 | Label("Tap for detail", systemImage: "arrow.right") 18 | .accessibilityLabel("Temperature in Celsius") 19 | .accessibilityValue("\(dayInfo.temperature) degrees") 20 | .labelStyle(.buttonIcon) 21 | .font(.caption2) 22 | } 23 | .frame(height: 130) 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /skydiving weather/Models/OpenWeatherData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OpenWeatherData.swift 3 | // skydiving weather 4 | // 5 | // Created by Léa Lescure on 02/01/2023. 6 | // 7 | 8 | import Foundation 9 | 10 | struct OpenMapWeatherData: Codable { 11 | var list: [OpenMapWeatherList] 12 | } 13 | 14 | struct OpenMapWeatherList: Codable { 15 | var weather: [OpenMapWeatherWeather] 16 | var main: OpenMapWeatherMain 17 | var wind: OpenMapWeatherWind 18 | var visibility: Double? 19 | var dt_txt: String? 20 | } 21 | 22 | struct OpenMapWeatherWeather: Codable { 23 | var id: Int? 24 | var main: String? 25 | var description: String? 26 | } 27 | 28 | struct OpenMapWeatherMain: Codable { 29 | var temp: Double? 30 | } 31 | 32 | struct OpenMapWeatherWind: Codable { 33 | var speed: Double? 34 | var deg: Double? 35 | } 36 | -------------------------------------------------------------------------------- /skydiving weather/Assets.xcassets/Theme/sky.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.988", 9 | "green" : "0.831", 10 | "red" : "0.467" 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.988", 27 | "green" : "0.831", 28 | "red" : "0.467" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /skydiving weather/Assets.xcassets/Theme/lightgray.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.808", 9 | "green" : "0.808", 10 | "red" : "0.820" 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.808", 27 | "green" : "0.808", 28 | "red" : "0.820" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /skydiving weather/Assets.xcassets/Theme/mediumorange.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x00", 9 | "green" : "0xA4", 10 | "red" : "0xF5" 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" : "0x00", 27 | "green" : "0xA4", 28 | "red" : "0xF5" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /skydiving weather/Assets.xcassets/Theme/okgreen.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.494", 9 | "green" : "0.765", 10 | "red" : "0.310" 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.494", 27 | "green" : "0.765", 28 | "red" : "0.310" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /skydiving weather/Assets.xcassets/Theme/impossiblered.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.176", 9 | "green" : "0.176", 10 | "red" : "0.847" 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.176", 27 | "green" : "0.176", 28 | "red" : "0.847" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /skydiving weather/Models/WeatherInfoByDayModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WeatherInfoByDayModel.swift 3 | // skydiving weather 4 | // 5 | // Created by Léa Lescure on 03/01/2023. 6 | // 7 | 8 | import Foundation 9 | 10 | struct WeatherInfoByDay: Identifiable, Codable { 11 | let id: UUID 12 | var temperature: Double 13 | var weatherSystemImage: String 14 | var date: String 15 | var windSpeed: Double 16 | var windOrientation: String 17 | var visibility: Double 18 | var color: String 19 | var description: String 20 | 21 | init(id: UUID = UUID(), temperature: Double, weatherSystemImage: String, date: String, windSpeed: Double, windOrientation: String, visibility: Double, color: String, description: String) { 22 | self.id = id 23 | self.temperature = temperature 24 | self.weatherSystemImage = weatherSystemImage 25 | self.date = date 26 | self.windSpeed = windSpeed 27 | self.windOrientation = windOrientation 28 | self.visibility = visibility 29 | self.color = color 30 | self.description = description 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /skydiving weather/Models/WeatherViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WeatherModel.swift 3 | // skydiving weather 4 | // 5 | // Created by Léa Lescure on 30/12/2022. 6 | // 7 | 8 | import Foundation 9 | 10 | class WeatherViewModel: ObservableObject { 11 | private let weatherService: WeatherService = WeatherService() 12 | @Published var weatherInfoByDay: [WeatherInfoByDay] = [] 13 | @Published var isFinishedLoading: Bool = false 14 | 15 | func fetchData(for dropzoneSelected: String) { 16 | let i = Dropzone.frenchDropzones.firstIndex(where: {$0.name == dropzoneSelected}) 17 | weatherService.fetchWeatherData(latitude: String(Dropzone.frenchDropzones[i!].latitude), longitude: String(Dropzone.frenchDropzones[i!].longitude)) { weather, error in 18 | guard error == nil else { 19 | print(error as Any) 20 | return 21 | } 22 | if let retrievedWeather = weather { 23 | DispatchQueue.main.async { 24 | self.weatherInfoByDay = retrievedWeather 25 | self.isFinishedLoading = true 26 | } 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /skydiving weather/Views/WeatherResultView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WeatherResultView.swift 3 | // skydiving weather 4 | // 5 | // Created by Léa Lescure on 23/12/2022. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct WeatherResultView: View { 11 | @Binding var dropzoneSelected: String 12 | var weather: WeatherViewModel = WeatherViewModel() 13 | 14 | var body: some View { 15 | VStack { 16 | Text(dropzoneSelected) 17 | .font(.title) 18 | .bold() 19 | .multilineTextAlignment(.center) 20 | .accessibilityAddTraits(.isHeader) 21 | NavigationStack { 22 | List { 23 | ForEach(weather.weatherInfoByDay.prefix(4)) { dayInfo in 24 | DayView(dayInfo: dayInfo) 25 | .listRowBackground(Color(dayInfo.color)) 26 | .listRowSeparatorTint(.white) 27 | } 28 | } 29 | .listStyle(.plain) 30 | .padding(.horizontal, 14) 31 | } 32 | 33 | } 34 | // Used to reset the value of dropzone to empty 35 | .onDisappear{ 36 | dropzoneSelected = "" 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Skydiving-app 2 | 3 | The aim of this app was to learn the basics of **SwiftUi** in 4 days. 4 | 5 | ---- 6 | 7 | Here is a short video of the app in action: 8 | 9 | https://user-images.githubusercontent.com/64603276/210509152-39df70b7-10c5-4b70-8d39-ee42b39ebd35.mp4 10 | 11 | ---- 12 | 13 | As a skydiver, one of our main concern is to know if the weather makes skydiving possible or not. 14 | 15 | It depends of three criteria : 16 | * **Wind strength:** it must be inferior to 35km/h 17 | * **Visibility:** it must be superior to 4km 18 | * **Lack of rain** 19 | 20 | I used the free API from [OpenWeather](https://openweathermap.org/). 21 | 22 | This app tells you if skydiving is possible in your dropzone for the next 4 days by giving you a short explanation on the weather as well as the key metrics (temperature, visibility, wind strength and wind orientation). 23 | 24 | Please note that the app uses data from OpenWeather for a given day at 12 o'clock. It means that if you use the app today at 1PM, you won't get today's weather. 25 | 26 | You can choose your dropzone among 36 dropzones in France. I hardcoded them using the [FFP website](https://www.ffp.asso.fr/ou-pratiquer/liste-de-toutes-les-structures-ffp/) and entered the city next to them in OpenWeather to have the longitude and latitude. 27 | -------------------------------------------------------------------------------- /skydiving weather/Views/Subviews/DayView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DayView.swift 3 | // skydiving weather 4 | // 5 | // Created by Léa Lescure on 03/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct DayView: View { 11 | @State private var isShowingKeyMetrics: Bool = false 12 | let dayInfo: WeatherInfoByDay 13 | 14 | var body: some View { 15 | VStack(alignment: .leading, spacing: 10) { 16 | Label(dayInfo.date, systemImage: dayInfo.weatherSystemImage) 17 | .labelStyle(.styledLabel) 18 | .accessibilityAddTraits(.isHeader) 19 | .accessibilityElement(children: .combine) 20 | .font(.title3) 21 | .bold() 22 | .padding(.leading, -20) 23 | if (isShowingKeyMetrics) { 24 | KeyMetricsView(dayInfo: dayInfo) 25 | } 26 | else { 27 | DescriptionView(dayInfo: dayInfo) 28 | } 29 | } 30 | .onTapGesture { 31 | isShowingKeyMetrics = !isShowingKeyMetrics 32 | } 33 | .padding() 34 | .foregroundColor(.white) 35 | // Used to have the stroke longer between each row 36 | .alignmentGuide( 37 | .listRowSeparatorLeading) { dimensions in 38 | dimensions[.leading] 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /skydiving weather/Views/Subviews/DropzoneAutocompleteView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SearchBarView.swift 3 | // skydiving weather 4 | // 5 | // Created by Léa Lescure on 25/12/2022. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct DropzoneAutocompleteView: View { 11 | 12 | @Binding var dropzoneSelected : String 13 | @Environment(\.dismiss) private var dismiss 14 | 15 | 16 | var body: some View { 17 | NavigationStack { 18 | List { 19 | ForEach(searchResults, id: \.self) { name in 20 | Text(name) 21 | .onTapGesture { 22 | dropzoneSelected = name 23 | dismiss() 24 | } 25 | } 26 | } 27 | } 28 | .searchable(text: $dropzoneSelected, placement: .navigationBarDrawer(displayMode: .always)) 29 | } 30 | 31 | var searchResults: [String] { 32 | if dropzoneSelected.isEmpty { 33 | return Dropzone.frenchDropzonesList.sorted() 34 | } else { 35 | return Dropzone.frenchDropzonesList.sorted().filter { $0.contains(dropzoneSelected) } 36 | } 37 | } 38 | } 39 | 40 | struct DropzoneAutocomplete_Previews: PreviewProvider { 41 | static var previews: some View { 42 | DropzoneAutocompleteView(dropzoneSelected: .constant("")) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /skydiving weather/Views/Subviews/LocalisationView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LocalisationView.swift 3 | // skydiving weather 4 | // 5 | // Created by Léa Lescure on 23/12/2022. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct LocalisationView: View { 11 | @Binding var dropzoneSelected: String 12 | @State var isShowingDropzoneList : Bool = false 13 | 14 | var body: some View{ 15 | VStack(alignment: .leading, spacing: 0) { 16 | Text("Drop Zone") 17 | .font(.custom("header", size: 10)) 18 | .foregroundColor(Color("lightgray")) 19 | TextField("", text: $dropzoneSelected) 20 | .disabled(true) 21 | .styledTextfield() 22 | } 23 | .padding(.bottom, 20) 24 | .padding(.top, 5) 25 | .padding(.horizontal, 20) 26 | .background(RoundedRectangle(cornerRadius: 10).foregroundColor(.white)) 27 | .padding(.horizontal, 40) 28 | .accessibilityLabel("Enter Dropzone") 29 | .onTapGesture { 30 | isShowingDropzoneList = true 31 | } 32 | .sheet(isPresented: $isShowingDropzoneList) 33 | { 34 | DropzoneAutocompleteView(dropzoneSelected: $dropzoneSelected) 35 | } 36 | } 37 | } 38 | 39 | struct LocalisationView_Previews: PreviewProvider { 40 | static var previews: some View { 41 | LocalisationView(dropzoneSelected: .constant("")) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /skydiving weather/Views/Subviews/KeyMetricsView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KeyMetricsView.swift 3 | // skydiving weather 4 | // 5 | // Created by Léa Lescure on 03/01/2023. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct KeyMetricsView: View { 11 | let dayInfo: WeatherInfoByDay 12 | 13 | var body: some View { 14 | HStack { 15 | VStack (alignment: .leading, spacing: 6) { 16 | Label("\(String(format:"%.0f", dayInfo.windSpeed)) km/h", systemImage: "wind") 17 | .accessibilityLabel("Speed of wind") 18 | .accessibilityValue("\(dayInfo.windSpeed) km/h") 19 | Label("\(String(format:"%.0f", dayInfo.temperature))°C", systemImage: "thermometer.medium") 20 | .accessibilityLabel("Temperature in Celsius") 21 | .accessibilityValue("\(dayInfo.temperature) degrees") 22 | } 23 | Spacer() 24 | .frame(width: 60) 25 | VStack (alignment: .leading, spacing: 6) { 26 | Label("\(dayInfo.windOrientation)", systemImage: "paperplane.circle") 27 | .accessibilityLabel("Wind orientation") 28 | .accessibilityValue("\(dayInfo.windOrientation)") 29 | Label("\(String(format:"%.0f", dayInfo.visibility)) km", systemImage: "binoculars") 30 | .accessibilityLabel("Visibility") 31 | .accessibilityValue("\(dayInfo.visibility) km") 32 | } 33 | } 34 | .frame(height: 130) 35 | .font(.subheadline) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /skydiving weather/Views/HomePageView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // skydiving weather 4 | // 5 | // Created by Léa Lescure on 22/12/2022. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct HomePageView: View { 11 | @StateObject var weatherVM: WeatherViewModel = WeatherViewModel() 12 | @State private var dropzoneSelected: String = "" 13 | 14 | var body: some View { 15 | NavigationStack { 16 | ZStack(alignment: .bottom) { 17 | GeometryReader { geo in 18 | Image("skydiving-homepage") 19 | .resizable() 20 | .aspectRatio(contentMode: .fill) 21 | .frame(maxWidth: geo.size.width) 22 | } 23 | .edgesIgnoringSafeArea(.all) 24 | VStack { 25 | LocalisationView(dropzoneSelected: $dropzoneSelected) 26 | VStack { 27 | Button(action : { 28 | if (!dropzoneSelected.isEmpty) { 29 | weatherVM.fetchData(for: dropzoneSelected) 30 | } 31 | }) { 32 | Label("Can I skydive?", systemImage: "airplane.departure") 33 | .bold() 34 | .padding(10) 35 | .labelStyle(.buttonIcon) 36 | // Use of .infinity to have the button size automatically adjust depending on the screen size 37 | .frame(maxWidth: .infinity) 38 | } 39 | .buttonStyle(.borderedProminent) 40 | .tint(Color("sky")) 41 | .padding(.bottom, 60) 42 | .padding(.horizontal, 40) 43 | } 44 | } 45 | .navigationDestination(isPresented: $weatherVM.isFinishedLoading) { 46 | WeatherResultView(dropzoneSelected: $dropzoneSelected, weather: weatherVM) 47 | } 48 | } 49 | } 50 | } 51 | } 52 | 53 | struct HomePageView_Previews: PreviewProvider { 54 | static var previews: some View { 55 | HomePageView() 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | # *.xcodeproj 44 | # 45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 46 | # hence it is not needed unless you have added a package configuration file to your project 47 | # .swiftpm 48 | 49 | .build/ 50 | 51 | # CocoaPods 52 | # 53 | # We recommend against adding the Pods directory to your .gitignore. However 54 | # you should judge for yourself, the pros and cons are mentioned at: 55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 56 | # 57 | # Pods/ 58 | # 59 | # Add this line if you want to avoid checking in source code from the Xcode workspace 60 | # *.xcworkspace 61 | 62 | # Carthage 63 | # 64 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 65 | # Carthage/Checkouts 66 | 67 | Carthage/Build/ 68 | 69 | # Accio dependency management 70 | Dependencies/ 71 | .accio/ 72 | 73 | # fastlane 74 | # 75 | # It is recommended to not store the screenshots in the git repo. 76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 77 | # For more information about the recommended setup visit: 78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 79 | 80 | fastlane/report.xml 81 | fastlane/Preview.html 82 | fastlane/screenshots/**/*.png 83 | fastlane/test_output 84 | 85 | # Code Injection 86 | # 87 | # After new code Injection tools there's a generated folder /iOSInjectionProject 88 | # https://github.com/johnno1962/injectionforxcode 89 | 90 | iOSInjectionProject/ 91 | -------------------------------------------------------------------------------- /skydiving weather.xcodeproj/xcshareddata/xcschemes/skydiving weather.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 58 | 59 | 60 | 61 | 67 | 69 | 75 | 76 | 77 | 78 | 80 | 81 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /skydiving weather/Models/DropZone.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DropZone.swift 3 | // skydiving weather 4 | // 5 | // Created by Léa Lescure on 23/12/2022. 6 | // 7 | 8 | import Foundation 9 | 10 | struct Dropzone: Identifiable { 11 | let id: UUID 12 | var name: String 13 | var latitude: Double 14 | var longitude: Double 15 | 16 | init(id: UUID = UUID(), name: String, latitude: Double, longitude: Double) { 17 | self.id = id 18 | self.name = name 19 | self.latitude = latitude 20 | self.longitude = longitude 21 | } 22 | } 23 | 24 | extension Dropzone { 25 | static let frenchDropzones: [Dropzone] = [ 26 | Dropzone(name: "Savoie Parachutisme", latitude: 45.6333, longitude: 5.9), 27 | Dropzone(name: "CERPS Gap-Tallard", latitude: 44.567, longitude: 6.083), 28 | Dropzone(name: "Vendée Evasion Parachutisme", latitude: 46.500, longitude: -1.783), 29 | Dropzone(name: "Europhénix 17 Royan parachutisme", latitude: 45.629, longitude: -1.028), 30 | Dropzone(name: "Abalone Parachutisme", latitude: 48.865, longitude: -1.556), 31 | Dropzone(name: "FlyAdrenaline", latitude: 50.155, longitude: 1.813), 32 | Dropzone(name: "Bouloc Skydive", latitude: 44.2553, longitude: 1.1382), 33 | Dropzone(name: "Skydive Frétoy", latitude: 49.5833, longitude: 3), 34 | Dropzone(name: "XLR Parachutisme", latitude: 45.511, longitude: -1.125), 35 | Dropzone(name: "Pau Skydive ccal", latitude: 43.433, longitude: -0.283), 36 | Dropzone(name: "Ecole de Parachutisme Du Valinco", latitude: 41.6753, longitude: 8.903), 37 | Dropzone(name: "Abeille Parachutisme", latitude: 49.4938, longitude: 0.1077), 38 | Dropzone(name: "Chute Libre Dordogne", latitude: 44.8022, longitude: 1.2146), 39 | Dropzone(name: "Big'Air Parachutisme Rochefort", latitude: 45.8667, longitude: -0.9667), 40 | Dropzone(name: "Mont Blanc Skydive", latitude: 45.9238, longitude: 6.8693), 41 | Dropzone(name: "Aero Tandem Celtic", latitude: 47.75, longitude: -2.6833), 42 | Dropzone(name: "Parachute Péronne", latitude: 49.9333, longitude: 2.9333), 43 | Dropzone(name: "Vertical T'Air Parachutisme", latitude: 44.6287, longitude: -1.1406), 44 | Dropzone(name: "Dragon Fly Parachutisme", latitude: 44.6201, longitude: 4.3899), 45 | Dropzone(name: "Skydive-Occitanie", latitude: 43.1976, longitude: 2.7614), 46 | Dropzone(name: "Skydive Roanne", latitude: 46.0333, longitude: 4), 47 | Dropzone(name: "Parachutisme 38", latitude: 45.3333, longitude: 5.35), 48 | Dropzone(name: "Parachutisme 42", latitude: 45.5833, longitude: 4.3167), 49 | Dropzone(name: "Para-Club du Puy", latitude: 45.0682, longitude: 3.7499), 50 | Dropzone(name: "Auvergne Parachutisme", latitude: 45.7797, longitude: 3.0863), 51 | Dropzone(name: "École de Parachutisme de Lyon Corbas", latitude: 45.6679, longitude: 4.8963), 52 | Dropzone(name: "Ecole de Parachutisme Besançon Franche-Comté", latitude: 47.2107, longitude: 6.067), 53 | Dropzone(name: "École Parachutisme Nord Franche Comté", latitude: 47.5167, longitude: 6.8), 54 | Dropzone(name: "Parachutisme71", latitude: 46.8186, longitude: 4.8336), 55 | Dropzone(name: "EFP Le Blanc", latitude: 47.8622, longitude: 1.9), 56 | Dropzone(name: "TOURS'N JUMP", latitude: 47.4167, longitude: 0.6667), 57 | Dropzone(name: "Centre Ecole Régional de Parachutisme", latitude: 48.5834, longitude: 7.743), 58 | Dropzone(name: "École Française de Parachutisme Lille Bondues", latitude: 50.702, longitude: 3.095), 59 | Dropzone(name: "Lens Parachutisme", latitude: 50.4855, longitude: 2.8305), 60 | Dropzone(name: "Air Libre Parachutisme", latitude: 49.8716, longitude: 1.0682), 61 | Dropzone(name: "Skydive Pujaut", latitude: 44, longitude: 4.7833), 62 | Dropzone(name: "Saumur Ecole de Parachutisme", latitude: 47.2667, longitude: -0.25), 63 | Dropzone(name: "Parachutisme Laval", latitude: 48.0667, longitude: -0.7667), 64 | Dropzone(name: "Parachute Club d'Aix en Provence", latitude: 43.5283, longitude: 5.4497) 65 | ] 66 | 67 | static let frenchDropzonesList: [String] = [ 68 | "Savoie Parachutisme", 69 | "CERPS Gap-Tallard", 70 | "Vendée Evasion Parachutisme", 71 | "Europhénix 17 Royan parachutisme", 72 | "Abalone Parachutisme", 73 | "FlyAdrenaline", 74 | "Bouloc Skydive", 75 | "Skydive Frétoy", 76 | "XLR Parachutisme", 77 | "Pau Skydive ccal", 78 | "Ecole de Parachutisme Du Valinco", 79 | "Abeille Parachutisme", 80 | "Chute Libre Dordogne", 81 | "Big'Air Parachutisme Rochefort", 82 | "Mont Blanc Skydive", 83 | "Aero Tandem Celtic", 84 | "Parachute Péronne", 85 | "Vertical T'Air Parachutisme", 86 | "Dragon Fly Parachutisme", 87 | "Skydive-Occitanie", 88 | "Skydive Roanne", 89 | "Parachutisme 38", 90 | "Parachutisme 42", 91 | "Para-Club du Puy", 92 | "Auvergne Parachutisme", 93 | "École de Parachutisme de Lyon Corbas", 94 | "Ecole de Parachutisme Besançon Franche-Comté", 95 | "École Parachutisme Nord Franche Comté", 96 | "Parachutisme71", 97 | "EFP Le Blanc", 98 | "TOURS'N JUMP", 99 | "Centre Ecole Régional de Parachutisme", 100 | "École Française de Parachutisme Lille Bondues", 101 | "Lens Parachutisme", 102 | "Air Libre Parachutisme", 103 | "Skydive Pujaut", 104 | "Saumur Ecole de Parachutisme", 105 | "Parachutisme Laval", 106 | "Parachute Club d'Aix en Provence", 107 | ] 108 | } 109 | -------------------------------------------------------------------------------- /skydiving weather/Services/WeatherService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WeatherService.swift 3 | // skydiving weather 4 | // 5 | // Created by Léa Lescure on 01/01/2023. 6 | // 7 | 8 | import Foundation 9 | 10 | public enum WebServiceControllerError: Error { 11 | case invalidUrl(String) 12 | case invalidPayload(URL) 13 | case forwared(Error) 14 | 15 | } 16 | 17 | extension Array { 18 | public mutating func append(_ newElement: Element?) { 19 | if let element = newElement { 20 | self.append(element) 21 | } 22 | } 23 | } 24 | 25 | public struct WeatherService { 26 | private let apiKey: String = "3cd9eaaf200ce8b8c0ad58e98b1c9b33" 27 | private let baseUrl: String = "https://api.openweathermap.org/data/2.5/forecast" 28 | 29 | func getWeekDay(date: String?)-> String?{ 30 | if let strDate = date { 31 | let dateFormatter = DateFormatter() 32 | let currentDate = Date() 33 | 34 | dateFormatter.dateFormat = "yyyy'-'MM'-'dd' 'HH':'mm':'ss" 35 | let convertedDate = dateFormatter.date(from: strDate) 36 | 37 | let hourFromDate = Calendar.current.component(.hour, from: convertedDate!) 38 | 39 | // Check if the current data is set for 12 o'clock 40 | // In that case we will get the data for the day 41 | if (hourFromDate == 12) { 42 | let dayFromDate = Calendar.current.component(.day, from: convertedDate!) 43 | let currentDay = Calendar.current.component(.day, from: currentDate) 44 | let difference = dayFromDate - currentDay 45 | 46 | // Get the day of the week 47 | dateFormatter.dateFormat = "EEEE" 48 | let weekDay = dateFormatter.string(from: convertedDate!) 49 | 50 | switch difference { 51 | case 0: 52 | return "Today" 53 | case 1: 54 | return "Tomorrow" 55 | default: 56 | return weekDay 57 | } 58 | } 59 | return nil 60 | } 61 | return nil 62 | } 63 | 64 | func convertVisibility(visibility: Double)->Double { 65 | return (round(visibility / 1000)) 66 | } 67 | 68 | func convertWindSpeed(speed: Double)->Double { 69 | return (round(speed * 3.6)) 70 | } 71 | 72 | func convertTemperature(temperature: Double)->Double { 73 | return (round(temperature)) 74 | } 75 | 76 | func convertWindDegree(degree: Double)->String { 77 | switch degree { 78 | case 0...45: 79 | return "North" 80 | case 45...90: 81 | return "North-East" 82 | case 90...135: 83 | return "East" 84 | case 135...180: 85 | return "South-East" 86 | case 180...225: 87 | return "South" 88 | case 225...270: 89 | return "South-West" 90 | case 270...315: 91 | return "West" 92 | default: 93 | return "North-West" 94 | } 95 | } 96 | 97 | func convertDescriptionInSystemImage(description: String)->String { 98 | switch description { 99 | case "Clear": 100 | return "sun.max.fill" 101 | case "Clouds": 102 | return "cloud.fill" 103 | case "Rain": 104 | return "cloud.rain.fill" 105 | case "Snow": 106 | return "cloud.snow.fill" 107 | case "Mist": 108 | return "cloud.fog.fill" 109 | default: 110 | return "cloud.bolt.fill" 111 | } 112 | } 113 | 114 | func getColor(temperature: Double, weatherType: String, visibility: Double, windSpeed: Double)->String { 115 | if (weatherType == "Clear" && visibility >= 3000 && windSpeed * 3.6 < 35) { 116 | return "okgreen" 117 | } 118 | else if (weatherType == "Rain" || weatherType == "Snow" || weatherType == "Thunderstorm") { 119 | return "impossiblered" 120 | } 121 | return "mediumorange" 122 | } 123 | 124 | func getDescription(temperature: Double, weatherType: String, visibility: Double, windSpeed: Double)->String { 125 | if (weatherType == "Clear" && visibility >= 3000 && windSpeed * 3.6 < 35 && temperature >= 10) { 126 | return "The weather is ideal for skydiving. The wind is less than 35 km/h. The sky is clear with a visibility higher than 3 km, without rain." 127 | } 128 | else if (weatherType == "Clear" && visibility >= 3000 && windSpeed * 3.6 < 35 && temperature < 10) { 129 | return "You can go skydiving but it will be cold! We lose 30 degrees between the ground and the temperature at 4000 meters. Check that your dropzone is open. Most of them are closed during winter." 130 | } 131 | else if (weatherType == "Rain") { 132 | return "Rain is expected all day, so there is very little chance of skydiving." 133 | } 134 | else if (weatherType == "Thunderstorm") { 135 | return "Thunderstorms are forecast for the day, creating unstable weather conditions. There is very little chance of skydiving." 136 | } 137 | else if (weatherType == "Snow") { 138 | return "Snow is forecast for the day, even if there is some sunshine, are you sure you want to try the -20°C up there ?" 139 | } 140 | else if (visibility < 3000) { 141 | return "The visibility is not good. But there may be some chance to skydive if the weather clears. Keep checking the weather forecast." 142 | } 143 | else if (windSpeed * 3.6 > 35) { 144 | return "It's too windy to go skydiving right now. Keep checking the weather forecast." 145 | } 146 | return "It's cloudy all day but if the clouds are high enough, skydiving might be possible!" 147 | } 148 | 149 | 150 | func fetchWeatherData(latitude: String, longitude: String, callback: @escaping ([WeatherInfoByDay]?, WebServiceControllerError?) -> Void) { 151 | 152 | let possibleUrl = "\(baseUrl)?lat=\(latitude)&lon=\(longitude)&appid=\(apiKey)&units=metric" 153 | 154 | if let url = URL(string: possibleUrl) { 155 | 156 | URLSession.shared.dataTask(with: url) { data, response, error in 157 | guard error == nil else { 158 | callback(nil, WebServiceControllerError.forwared(error!)) 159 | return 160 | } 161 | 162 | if let dataFromWeather = data, let _ = response { 163 | let decoder = JSONDecoder() 164 | 165 | do { 166 | let weatherData = try decoder.decode(OpenMapWeatherData.self, from: dataFromWeather) 167 | let weatherDataSize = weatherData.list.count - 1 168 | var weatherInfoByDay: [WeatherInfoByDay] = [] 169 | 170 | for i in 0...weatherDataSize { 171 | // Create an array of data dated at 12 o'clock of the 5 following days 172 | if let weekDay = getWeekDay(date: weatherData.list[i].dt_txt) 173 | { 174 | weatherInfoByDay.append(WeatherInfoByDay(temperature: convertTemperature(temperature: weatherData.list[i].main.temp!), 175 | weatherSystemImage: convertDescriptionInSystemImage(description: weatherData.list[i].weather.first!.main!), 176 | date: weekDay, 177 | windSpeed: convertWindSpeed(speed: weatherData.list[i].wind.speed!), 178 | windOrientation: convertWindDegree(degree: weatherData.list[i].wind.deg!), 179 | visibility: convertVisibility(visibility: weatherData.list[i].visibility!), 180 | color: getColor(temperature: weatherData.list[i].main.temp!, 181 | weatherType: weatherData.list[i].weather.first!.main!, 182 | visibility: weatherData.list[i].visibility!, 183 | windSpeed: weatherData.list[i].wind.speed!), 184 | description: getDescription(temperature: weatherData.list[i].main.temp!, 185 | weatherType: weatherData.list[i].weather.first!.main!, 186 | visibility: weatherData.list[i].visibility!, 187 | windSpeed: weatherData.list[i].wind.speed!) 188 | )) 189 | } 190 | } 191 | callback(weatherInfoByDay, nil) 192 | } 193 | catch let error { 194 | callback(nil, WebServiceControllerError.forwared(error)) 195 | } 196 | } else { 197 | callback(nil, WebServiceControllerError.invalidPayload(url)) 198 | } 199 | }.resume() 200 | } else { 201 | callback(nil, WebServiceControllerError.invalidUrl(possibleUrl)) 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /skydiving weather.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | DB48152E29655D720034273C /* StyledLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB48152D29655D720034273C /* StyledLabel.swift */; }; 11 | DB72B37D295F769900EE326C /* WeatherViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72B37C295F769900EE326C /* WeatherViewModel.swift */; }; 12 | DBBD21D02955F837004E0EDE /* ButtonIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBD21CF2955F837004E0EDE /* ButtonIcon.swift */; }; 13 | DBBD21D3295602C1004E0EDE /* DropZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBD21D2295602C1004E0EDE /* DropZone.swift */; }; 14 | DBBD21D529564AD8004E0EDE /* StyledTextfield.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBD21D429564AD8004E0EDE /* StyledTextfield.swift */; }; 15 | DBE2CAE22958DB9700F92290 /* DropzoneAutocompleteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE2CAE12958DB9700F92290 /* DropzoneAutocompleteView.swift */; }; 16 | DBE7BB732961B8B000D805AA /* WeatherService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE7BB722961B8B000D805AA /* WeatherService.swift */; }; 17 | DBE7BB7629631F6B00D805AA /* OpenWeatherData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE7BB7529631F6B00D805AA /* OpenWeatherData.swift */; }; 18 | DBE7BB79296462CB00D805AA /* WeatherInfoByDayModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE7BB78296462CB00D805AA /* WeatherInfoByDayModel.swift */; }; 19 | DBE7BB7B29646B2200D805AA /* DayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE7BB7A29646B2200D805AA /* DayView.swift */; }; 20 | DBE7BB802964B5F200D805AA /* KeyMetricsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE7BB7F2964B5F200D805AA /* KeyMetricsView.swift */; }; 21 | DBE7BB822964B60000D805AA /* DescriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE7BB812964B60000D805AA /* DescriptionView.swift */; }; 22 | DBE842012954CB58005D7F70 /* skydiving_weatherApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE842002954CB58005D7F70 /* skydiving_weatherApp.swift */; }; 23 | DBE842032954CB58005D7F70 /* HomePageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE842022954CB58005D7F70 /* HomePageView.swift */; }; 24 | DBE842052954CB5A005D7F70 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DBE842042954CB5A005D7F70 /* Assets.xcassets */; }; 25 | DBE842082954CB5A005D7F70 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DBE842072954CB5A005D7F70 /* Preview Assets.xcassets */; }; 26 | DBE8420F2955AB45005D7F70 /* WeatherResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE8420E2955AB45005D7F70 /* WeatherResultView.swift */; }; 27 | DBE842112955AC6F005D7F70 /* LocalisationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE842102955AC6F005D7F70 /* LocalisationView.swift */; }; 28 | /* End PBXBuildFile section */ 29 | 30 | /* Begin PBXFileReference section */ 31 | DB48152D29655D720034273C /* StyledLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StyledLabel.swift; sourceTree = ""; }; 32 | DB72B37C295F769900EE326C /* WeatherViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherViewModel.swift; sourceTree = ""; }; 33 | DBBD21CF2955F837004E0EDE /* ButtonIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIcon.swift; sourceTree = ""; }; 34 | DBBD21D2295602C1004E0EDE /* DropZone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropZone.swift; sourceTree = ""; }; 35 | DBBD21D429564AD8004E0EDE /* StyledTextfield.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StyledTextfield.swift; sourceTree = ""; }; 36 | DBE2CAE12958DB9700F92290 /* DropzoneAutocompleteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropzoneAutocompleteView.swift; sourceTree = ""; }; 37 | DBE7BB722961B8B000D805AA /* WeatherService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherService.swift; sourceTree = ""; }; 38 | DBE7BB742962E75000D805AA /* skydiving-weather-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "skydiving-weather-Info.plist"; sourceTree = SOURCE_ROOT; }; 39 | DBE7BB7529631F6B00D805AA /* OpenWeatherData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenWeatherData.swift; sourceTree = ""; }; 40 | DBE7BB78296462CB00D805AA /* WeatherInfoByDayModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherInfoByDayModel.swift; sourceTree = ""; }; 41 | DBE7BB7A29646B2200D805AA /* DayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DayView.swift; sourceTree = ""; }; 42 | DBE7BB7F2964B5F200D805AA /* KeyMetricsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyMetricsView.swift; sourceTree = ""; }; 43 | DBE7BB812964B60000D805AA /* DescriptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DescriptionView.swift; sourceTree = ""; }; 44 | DBE841FD2954CB58005D7F70 /* skydiving weather.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "skydiving weather.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | DBE842002954CB58005D7F70 /* skydiving_weatherApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = skydiving_weatherApp.swift; sourceTree = ""; }; 46 | DBE842022954CB58005D7F70 /* HomePageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomePageView.swift; sourceTree = ""; }; 47 | DBE842042954CB5A005D7F70 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 48 | DBE842072954CB5A005D7F70 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 49 | DBE8420E2955AB45005D7F70 /* WeatherResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherResultView.swift; sourceTree = ""; }; 50 | DBE842102955AC6F005D7F70 /* LocalisationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalisationView.swift; sourceTree = ""; }; 51 | /* End PBXFileReference section */ 52 | 53 | /* Begin PBXFrameworksBuildPhase section */ 54 | DBE841FA2954CB58005D7F70 /* Frameworks */ = { 55 | isa = PBXFrameworksBuildPhase; 56 | buildActionMask = 2147483647; 57 | files = ( 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | /* End PBXFrameworksBuildPhase section */ 62 | 63 | /* Begin PBXGroup section */ 64 | DB72B37E295F867D00EE326C /* Views */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | DBE7BB7E2964A97600D805AA /* Subviews */, 68 | DBE842022954CB58005D7F70 /* HomePageView.swift */, 69 | DBE8420E2955AB45005D7F70 /* WeatherResultView.swift */, 70 | ); 71 | path = Views; 72 | sourceTree = ""; 73 | }; 74 | DBBD21CA2955E489004E0EDE /* Models */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | DB72B37C295F769900EE326C /* WeatherViewModel.swift */, 78 | DBE7BB78296462CB00D805AA /* WeatherInfoByDayModel.swift */, 79 | DBE7BB7529631F6B00D805AA /* OpenWeatherData.swift */, 80 | DBBD21D2295602C1004E0EDE /* DropZone.swift */, 81 | ); 82 | path = Models; 83 | sourceTree = ""; 84 | }; 85 | DBBD21D12955F9BC004E0EDE /* Style */ = { 86 | isa = PBXGroup; 87 | children = ( 88 | DBBD21CF2955F837004E0EDE /* ButtonIcon.swift */, 89 | DBBD21D429564AD8004E0EDE /* StyledTextfield.swift */, 90 | DB48152D29655D720034273C /* StyledLabel.swift */, 91 | ); 92 | path = Style; 93 | sourceTree = ""; 94 | }; 95 | DBE7BB712961B89E00D805AA /* Services */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | DBE7BB722961B8B000D805AA /* WeatherService.swift */, 99 | ); 100 | path = Services; 101 | sourceTree = ""; 102 | }; 103 | DBE7BB7E2964A97600D805AA /* Subviews */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | DBE842102955AC6F005D7F70 /* LocalisationView.swift */, 107 | DBE2CAE12958DB9700F92290 /* DropzoneAutocompleteView.swift */, 108 | DBE7BB7A29646B2200D805AA /* DayView.swift */, 109 | DBE7BB7F2964B5F200D805AA /* KeyMetricsView.swift */, 110 | DBE7BB812964B60000D805AA /* DescriptionView.swift */, 111 | ); 112 | path = Subviews; 113 | sourceTree = ""; 114 | }; 115 | DBE841F42954CB57005D7F70 = { 116 | isa = PBXGroup; 117 | children = ( 118 | DBE841FF2954CB58005D7F70 /* skydiving weather */, 119 | DBE841FE2954CB58005D7F70 /* Products */, 120 | ); 121 | sourceTree = ""; 122 | }; 123 | DBE841FE2954CB58005D7F70 /* Products */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | DBE841FD2954CB58005D7F70 /* skydiving weather.app */, 127 | ); 128 | name = Products; 129 | sourceTree = ""; 130 | }; 131 | DBE841FF2954CB58005D7F70 /* skydiving weather */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | DBE7BB742962E75000D805AA /* skydiving-weather-Info.plist */, 135 | DBE7BB712961B89E00D805AA /* Services */, 136 | DB72B37E295F867D00EE326C /* Views */, 137 | DBBD21D12955F9BC004E0EDE /* Style */, 138 | DBBD21CA2955E489004E0EDE /* Models */, 139 | DBE842002954CB58005D7F70 /* skydiving_weatherApp.swift */, 140 | DBE842042954CB5A005D7F70 /* Assets.xcassets */, 141 | DBE842062954CB5A005D7F70 /* Preview Content */, 142 | ); 143 | path = "skydiving weather"; 144 | sourceTree = ""; 145 | }; 146 | DBE842062954CB5A005D7F70 /* Preview Content */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | DBE842072954CB5A005D7F70 /* Preview Assets.xcassets */, 150 | ); 151 | path = "Preview Content"; 152 | sourceTree = ""; 153 | }; 154 | /* End PBXGroup section */ 155 | 156 | /* Begin PBXNativeTarget section */ 157 | DBE841FC2954CB58005D7F70 /* skydiving weather */ = { 158 | isa = PBXNativeTarget; 159 | buildConfigurationList = DBE8420B2954CB5A005D7F70 /* Build configuration list for PBXNativeTarget "skydiving weather" */; 160 | buildPhases = ( 161 | DBE841F92954CB58005D7F70 /* Sources */, 162 | DBE841FA2954CB58005D7F70 /* Frameworks */, 163 | DBE841FB2954CB58005D7F70 /* Resources */, 164 | ); 165 | buildRules = ( 166 | ); 167 | dependencies = ( 168 | ); 169 | name = "skydiving weather"; 170 | productName = "skydiving weather"; 171 | productReference = DBE841FD2954CB58005D7F70 /* skydiving weather.app */; 172 | productType = "com.apple.product-type.application"; 173 | }; 174 | /* End PBXNativeTarget section */ 175 | 176 | /* Begin PBXProject section */ 177 | DBE841F52954CB57005D7F70 /* Project object */ = { 178 | isa = PBXProject; 179 | attributes = { 180 | BuildIndependentTargetsInParallel = 1; 181 | LastSwiftUpdateCheck = 1420; 182 | LastUpgradeCheck = 1420; 183 | TargetAttributes = { 184 | DBE841FC2954CB58005D7F70 = { 185 | CreatedOnToolsVersion = 14.2; 186 | }; 187 | }; 188 | }; 189 | buildConfigurationList = DBE841F82954CB57005D7F70 /* Build configuration list for PBXProject "skydiving weather" */; 190 | compatibilityVersion = "Xcode 14.0"; 191 | developmentRegion = en; 192 | hasScannedForEncodings = 0; 193 | knownRegions = ( 194 | en, 195 | Base, 196 | ); 197 | mainGroup = DBE841F42954CB57005D7F70; 198 | productRefGroup = DBE841FE2954CB58005D7F70 /* Products */; 199 | projectDirPath = ""; 200 | projectRoot = ""; 201 | targets = ( 202 | DBE841FC2954CB58005D7F70 /* skydiving weather */, 203 | ); 204 | }; 205 | /* End PBXProject section */ 206 | 207 | /* Begin PBXResourcesBuildPhase section */ 208 | DBE841FB2954CB58005D7F70 /* Resources */ = { 209 | isa = PBXResourcesBuildPhase; 210 | buildActionMask = 2147483647; 211 | files = ( 212 | DBE842082954CB5A005D7F70 /* Preview Assets.xcassets in Resources */, 213 | DBE842052954CB5A005D7F70 /* Assets.xcassets in Resources */, 214 | ); 215 | runOnlyForDeploymentPostprocessing = 0; 216 | }; 217 | /* End PBXResourcesBuildPhase section */ 218 | 219 | /* Begin PBXSourcesBuildPhase section */ 220 | DBE841F92954CB58005D7F70 /* Sources */ = { 221 | isa = PBXSourcesBuildPhase; 222 | buildActionMask = 2147483647; 223 | files = ( 224 | DBE842032954CB58005D7F70 /* HomePageView.swift in Sources */, 225 | DB48152E29655D720034273C /* StyledLabel.swift in Sources */, 226 | DBE7BB7B29646B2200D805AA /* DayView.swift in Sources */, 227 | DBBD21D529564AD8004E0EDE /* StyledTextfield.swift in Sources */, 228 | DBE7BB79296462CB00D805AA /* WeatherInfoByDayModel.swift in Sources */, 229 | DBE8420F2955AB45005D7F70 /* WeatherResultView.swift in Sources */, 230 | DBBD21D3295602C1004E0EDE /* DropZone.swift in Sources */, 231 | DBE7BB732961B8B000D805AA /* WeatherService.swift in Sources */, 232 | DBBD21D02955F837004E0EDE /* ButtonIcon.swift in Sources */, 233 | DBE7BB7629631F6B00D805AA /* OpenWeatherData.swift in Sources */, 234 | DBE2CAE22958DB9700F92290 /* DropzoneAutocompleteView.swift in Sources */, 235 | DBE842112955AC6F005D7F70 /* LocalisationView.swift in Sources */, 236 | DB72B37D295F769900EE326C /* WeatherViewModel.swift in Sources */, 237 | DBE7BB802964B5F200D805AA /* KeyMetricsView.swift in Sources */, 238 | DBE842012954CB58005D7F70 /* skydiving_weatherApp.swift in Sources */, 239 | DBE7BB822964B60000D805AA /* DescriptionView.swift in Sources */, 240 | ); 241 | runOnlyForDeploymentPostprocessing = 0; 242 | }; 243 | /* End PBXSourcesBuildPhase section */ 244 | 245 | /* Begin XCBuildConfiguration section */ 246 | DBE842092954CB5A005D7F70 /* Debug */ = { 247 | isa = XCBuildConfiguration; 248 | buildSettings = { 249 | ALWAYS_SEARCH_USER_PATHS = NO; 250 | CLANG_ANALYZER_NONNULL = YES; 251 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 252 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 253 | CLANG_ENABLE_MODULES = YES; 254 | CLANG_ENABLE_OBJC_ARC = YES; 255 | CLANG_ENABLE_OBJC_WEAK = YES; 256 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 257 | CLANG_WARN_BOOL_CONVERSION = YES; 258 | CLANG_WARN_COMMA = YES; 259 | CLANG_WARN_CONSTANT_CONVERSION = YES; 260 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 261 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 262 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 263 | CLANG_WARN_EMPTY_BODY = YES; 264 | CLANG_WARN_ENUM_CONVERSION = YES; 265 | CLANG_WARN_INFINITE_RECURSION = YES; 266 | CLANG_WARN_INT_CONVERSION = YES; 267 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 268 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 269 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 270 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 271 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 272 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 273 | CLANG_WARN_STRICT_PROTOTYPES = YES; 274 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 275 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 276 | CLANG_WARN_UNREACHABLE_CODE = YES; 277 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 278 | COPY_PHASE_STRIP = NO; 279 | DEBUG_INFORMATION_FORMAT = dwarf; 280 | ENABLE_STRICT_OBJC_MSGSEND = YES; 281 | ENABLE_TESTABILITY = YES; 282 | GCC_C_LANGUAGE_STANDARD = gnu11; 283 | GCC_DYNAMIC_NO_PIC = NO; 284 | GCC_NO_COMMON_BLOCKS = YES; 285 | GCC_OPTIMIZATION_LEVEL = 0; 286 | GCC_PREPROCESSOR_DEFINITIONS = ( 287 | "DEBUG=1", 288 | "$(inherited)", 289 | ); 290 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 291 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 292 | GCC_WARN_UNDECLARED_SELECTOR = YES; 293 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 294 | GCC_WARN_UNUSED_FUNCTION = YES; 295 | GCC_WARN_UNUSED_VARIABLE = YES; 296 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = NO; 297 | IPHONEOS_DEPLOYMENT_TARGET = 16.1; 298 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 299 | MTL_FAST_MATH = YES; 300 | ONLY_ACTIVE_ARCH = YES; 301 | SDKROOT = iphoneos; 302 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 303 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 304 | }; 305 | name = Debug; 306 | }; 307 | DBE8420A2954CB5A005D7F70 /* Release */ = { 308 | isa = XCBuildConfiguration; 309 | buildSettings = { 310 | ALWAYS_SEARCH_USER_PATHS = NO; 311 | CLANG_ANALYZER_NONNULL = YES; 312 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 313 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 314 | CLANG_ENABLE_MODULES = YES; 315 | CLANG_ENABLE_OBJC_ARC = YES; 316 | CLANG_ENABLE_OBJC_WEAK = YES; 317 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 318 | CLANG_WARN_BOOL_CONVERSION = YES; 319 | CLANG_WARN_COMMA = YES; 320 | CLANG_WARN_CONSTANT_CONVERSION = YES; 321 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 322 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 323 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 324 | CLANG_WARN_EMPTY_BODY = YES; 325 | CLANG_WARN_ENUM_CONVERSION = YES; 326 | CLANG_WARN_INFINITE_RECURSION = YES; 327 | CLANG_WARN_INT_CONVERSION = YES; 328 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 329 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 330 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 331 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 332 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 333 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 334 | CLANG_WARN_STRICT_PROTOTYPES = YES; 335 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 336 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 337 | CLANG_WARN_UNREACHABLE_CODE = YES; 338 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 339 | COPY_PHASE_STRIP = NO; 340 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 341 | ENABLE_NS_ASSERTIONS = NO; 342 | ENABLE_STRICT_OBJC_MSGSEND = YES; 343 | GCC_C_LANGUAGE_STANDARD = gnu11; 344 | GCC_NO_COMMON_BLOCKS = YES; 345 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 346 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 347 | GCC_WARN_UNDECLARED_SELECTOR = YES; 348 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 349 | GCC_WARN_UNUSED_FUNCTION = YES; 350 | GCC_WARN_UNUSED_VARIABLE = YES; 351 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = NO; 352 | IPHONEOS_DEPLOYMENT_TARGET = 16.1; 353 | MTL_ENABLE_DEBUG_INFO = NO; 354 | MTL_FAST_MATH = YES; 355 | SDKROOT = iphoneos; 356 | SWIFT_COMPILATION_MODE = wholemodule; 357 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 358 | VALIDATE_PRODUCT = YES; 359 | }; 360 | name = Release; 361 | }; 362 | DBE8420C2954CB5A005D7F70 /* Debug */ = { 363 | isa = XCBuildConfiguration; 364 | buildSettings = { 365 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 366 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 367 | CODE_SIGN_STYLE = Automatic; 368 | CURRENT_PROJECT_VERSION = 1; 369 | DEVELOPMENT_ASSET_PATHS = "\"skydiving weather/Preview Content\""; 370 | DEVELOPMENT_TEAM = 4S2R248368; 371 | ENABLE_PREVIEWS = YES; 372 | GENERATE_INFOPLIST_FILE = YES; 373 | INFOPLIST_FILE = "skydiving-weather-Info.plist"; 374 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 375 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 376 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 377 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 378 | LD_RUNPATH_SEARCH_PATHS = ( 379 | "$(inherited)", 380 | "@executable_path/Frameworks", 381 | ); 382 | MARKETING_VERSION = 1.0; 383 | PRODUCT_BUNDLE_IDENTIFIER = "Lea-Lescure.skydiving-weather"; 384 | PRODUCT_NAME = "$(TARGET_NAME)"; 385 | SWIFT_EMIT_LOC_STRINGS = YES; 386 | SWIFT_VERSION = 5.0; 387 | TARGETED_DEVICE_FAMILY = "1,2"; 388 | }; 389 | name = Debug; 390 | }; 391 | DBE8420D2954CB5A005D7F70 /* Release */ = { 392 | isa = XCBuildConfiguration; 393 | buildSettings = { 394 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 395 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 396 | CODE_SIGN_STYLE = Automatic; 397 | CURRENT_PROJECT_VERSION = 1; 398 | DEVELOPMENT_ASSET_PATHS = "\"skydiving weather/Preview Content\""; 399 | DEVELOPMENT_TEAM = 4S2R248368; 400 | ENABLE_PREVIEWS = YES; 401 | GENERATE_INFOPLIST_FILE = YES; 402 | INFOPLIST_FILE = "skydiving-weather-Info.plist"; 403 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 404 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 405 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 406 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 407 | LD_RUNPATH_SEARCH_PATHS = ( 408 | "$(inherited)", 409 | "@executable_path/Frameworks", 410 | ); 411 | MARKETING_VERSION = 1.0; 412 | PRODUCT_BUNDLE_IDENTIFIER = "Lea-Lescure.skydiving-weather"; 413 | PRODUCT_NAME = "$(TARGET_NAME)"; 414 | SWIFT_EMIT_LOC_STRINGS = YES; 415 | SWIFT_VERSION = 5.0; 416 | TARGETED_DEVICE_FAMILY = "1,2"; 417 | }; 418 | name = Release; 419 | }; 420 | /* End XCBuildConfiguration section */ 421 | 422 | /* Begin XCConfigurationList section */ 423 | DBE841F82954CB57005D7F70 /* Build configuration list for PBXProject "skydiving weather" */ = { 424 | isa = XCConfigurationList; 425 | buildConfigurations = ( 426 | DBE842092954CB5A005D7F70 /* Debug */, 427 | DBE8420A2954CB5A005D7F70 /* Release */, 428 | ); 429 | defaultConfigurationIsVisible = 0; 430 | defaultConfigurationName = Release; 431 | }; 432 | DBE8420B2954CB5A005D7F70 /* Build configuration list for PBXNativeTarget "skydiving weather" */ = { 433 | isa = XCConfigurationList; 434 | buildConfigurations = ( 435 | DBE8420C2954CB5A005D7F70 /* Debug */, 436 | DBE8420D2954CB5A005D7F70 /* Release */, 437 | ); 438 | defaultConfigurationIsVisible = 0; 439 | defaultConfigurationName = Release; 440 | }; 441 | /* End XCConfigurationList section */ 442 | }; 443 | rootObject = DBE841F52954CB57005D7F70 /* Project object */; 444 | } 445 | --------------------------------------------------------------------------------