├── 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 |
--------------------------------------------------------------------------------