feat: ✨ Ability to view stations from the API
Addition of a single component for stations; creation of structure; creation of function to retrieve bikes in real time
This commit is contained in:
parent
752a1f8b32
commit
701d163547
@ -11,6 +11,9 @@
|
||||
2C5BDABF2AA3611000DBEC93 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C5BDABE2AA3611000DBEC93 /* ContentView.swift */; };
|
||||
2C5BDAC12AA3611000DBEC93 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C5BDAC02AA3611000DBEC93 /* Assets.xcassets */; };
|
||||
2C5BDAC52AA3611000DBEC93 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C5BDAC42AA3611000DBEC93 /* Preview Assets.xcassets */; };
|
||||
2CDC317E2AA3654800BF98B9 /* VelibStationStruct.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CDC317D2AA3654800BF98B9 /* VelibStationStruct.swift */; };
|
||||
2CDC31802AA3672600BF98B9 /* StationComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CDC317F2AA3672600BF98B9 /* StationComponent.swift */; };
|
||||
2CDC31822AA387AB00BF98B9 /* fetchVelibData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CDC31812AA387AB00BF98B9 /* fetchVelibData.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
@ -20,6 +23,9 @@
|
||||
2C5BDAC02AA3611000DBEC93 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
2C5BDAC22AA3611000DBEC93 /* velibtracker.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = velibtracker.entitlements; sourceTree = "<group>"; };
|
||||
2C5BDAC42AA3611000DBEC93 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||
2CDC317D2AA3654800BF98B9 /* VelibStationStruct.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VelibStationStruct.swift; sourceTree = "<group>"; };
|
||||
2CDC317F2AA3672600BF98B9 /* StationComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StationComponent.swift; sourceTree = "<group>"; };
|
||||
2CDC31812AA387AB00BF98B9 /* fetchVelibData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = fetchVelibData.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -52,11 +58,14 @@
|
||||
2C5BDABB2AA3611000DBEC93 /* velibtracker */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2CDC317C2AA3653200BF98B9 /* struct */,
|
||||
2C5BDACB2AA3632C00DBEC93 /* components */,
|
||||
2C5BDABC2AA3611000DBEC93 /* velibtrackerApp.swift */,
|
||||
2C5BDABE2AA3611000DBEC93 /* ContentView.swift */,
|
||||
2C5BDAC02AA3611000DBEC93 /* Assets.xcassets */,
|
||||
2C5BDAC22AA3611000DBEC93 /* velibtracker.entitlements */,
|
||||
2C5BDAC32AA3611000DBEC93 /* Preview Content */,
|
||||
2CDC31812AA387AB00BF98B9 /* fetchVelibData.swift */,
|
||||
);
|
||||
path = velibtracker;
|
||||
sourceTree = "<group>";
|
||||
@ -69,6 +78,22 @@
|
||||
path = "Preview Content";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2C5BDACB2AA3632C00DBEC93 /* components */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2CDC317F2AA3672600BF98B9 /* StationComponent.swift */,
|
||||
);
|
||||
path = components;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
2CDC317C2AA3653200BF98B9 /* struct */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2CDC317D2AA3654800BF98B9 /* VelibStationStruct.swift */,
|
||||
);
|
||||
path = struct;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -139,7 +164,10 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2CDC317E2AA3654800BF98B9 /* VelibStationStruct.swift in Sources */,
|
||||
2C5BDABF2AA3611000DBEC93 /* ContentView.swift in Sources */,
|
||||
2CDC31822AA387AB00BF98B9 /* fetchVelibData.swift in Sources */,
|
||||
2CDC31802AA3672600BF98B9 /* StationComponent.swift in Sources */,
|
||||
2C5BDABD2AA3611000DBEC93 /* velibtrackerApp.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Bucket
|
||||
uuid = "E086F483-B1A2-457D-A7AA-DFBB29D4A987"
|
||||
type = "1"
|
||||
version = "2.0">
|
||||
</Bucket>
|
@ -9,16 +9,20 @@ import SwiftUI
|
||||
|
||||
struct ContentView: View {
|
||||
var body: some View {
|
||||
VStack {
|
||||
Image(systemName: "globe")
|
||||
.imageScale(.large)
|
||||
.foregroundColor(.accentColor)
|
||||
Text("Hello, world!")
|
||||
NavigationView {
|
||||
ScrollView {
|
||||
ForEach(velibStations, id: \.stationcode) { station in
|
||||
StationComponent(station: station)
|
||||
.padding(.bottom, 16)
|
||||
}
|
||||
}
|
||||
.navigationBarTitle("Stations Vélib")
|
||||
}
|
||||
.padding()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct ContentView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ContentView()
|
||||
|
48
velibtracker/components/StationComponent.swift
Normal file
48
velibtracker/components/StationComponent.swift
Normal file
@ -0,0 +1,48 @@
|
||||
//
|
||||
// StationComponent.swift
|
||||
// velibtracker
|
||||
//
|
||||
// Created by Louis Gallet on 02/09/2023.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct StationComponent: View {
|
||||
|
||||
let station: VelibStation
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text(station.name)
|
||||
.font(.title)
|
||||
.foregroundColor(.primary)
|
||||
|
||||
HStack {
|
||||
Text("Capacité: \(station.capacity)")
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("Disponibles: \(station.numbikesavailable)")
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.background(Color.white)
|
||||
.cornerRadius(10)
|
||||
.shadow(radius: 5)
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 8)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct StationComponent_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
StationComponent(station: test[1])
|
||||
}
|
||||
}
|
52
velibtracker/fetchVelibData.swift
Normal file
52
velibtracker/fetchVelibData.swift
Normal file
@ -0,0 +1,52 @@
|
||||
//
|
||||
// fetchVelibData.swift
|
||||
// velibtracker
|
||||
//
|
||||
// Created by Louis Gallet on 02/09/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
var velibStations: [VelibStation] = []
|
||||
|
||||
import Foundation
|
||||
|
||||
func fetchVelibData() {
|
||||
// L'URL de l'API Vélib
|
||||
let apiUrl = URL(string: "https://opendata.paris.fr/api/explore/v2.1/catalog/datasets/velib-disponibilite-en-temps-reel/records?select=stationcode,name,capacity,numdocksavailable,numbikesavailable,mechanical,ebike,coordonnees_geo")!
|
||||
|
||||
// Créez une session URLSession pour effectuer la requête
|
||||
let session = URLSession.shared
|
||||
|
||||
// Créez la tâche de requête
|
||||
let task = session.dataTask(with: apiUrl) { (data, response, error) in
|
||||
// Vérifiez s'il y a des erreurs
|
||||
if let error = error {
|
||||
print("Erreur de requête : \(error.localizedDescription)")
|
||||
return
|
||||
}
|
||||
|
||||
// Vérifiez si les données sont présentes
|
||||
guard let data = data else {
|
||||
print("Aucune donnée reçue.")
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
// Décodez les données en utilisant le décodeur JSON
|
||||
let decoder = JSONDecoder()
|
||||
let velibResponse = try decoder.decode(VelibResponse.self, from: data)
|
||||
|
||||
// Stockez les données dans la variable globale velibStations
|
||||
velibStations = velibResponse.results
|
||||
|
||||
print("Données Vélib récupérées avec succès.")
|
||||
} catch {
|
||||
print("Erreur lors du décodage JSON : \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
|
||||
// Lancez la tâche de requête
|
||||
task.resume()
|
||||
}
|
75
velibtracker/struct/VelibStationStruct.swift
Normal file
75
velibtracker/struct/VelibStationStruct.swift
Normal file
@ -0,0 +1,75 @@
|
||||
//
|
||||
// VelibStationStruct.swift
|
||||
// velibtracker
|
||||
//
|
||||
// Created by Louis Gallet on 02/09/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct VelibResponse: Codable {
|
||||
let totalCount: Int
|
||||
let results: [VelibStation]
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case totalCount = "total_count"
|
||||
case results
|
||||
}
|
||||
}
|
||||
|
||||
struct VelibStation: Codable {
|
||||
let stationcode: String
|
||||
let name: String
|
||||
let capacity: Int
|
||||
let numdocksavailable: Int
|
||||
let numbikesavailable: Int
|
||||
let mechanical: Int
|
||||
let ebike: Int
|
||||
let coordonnees_geo: Coordinates
|
||||
|
||||
}
|
||||
|
||||
struct Coordinates: Codable {
|
||||
let lon: Double
|
||||
let lat: Double
|
||||
}
|
||||
|
||||
let test = [
|
||||
VelibStation(stationcode: "293", name: "Test", capacity: 3, numdocksavailable: 3, numbikesavailable: 3, mechanical: 3, ebike: 1, coordonnees_geo: Coordinates(lon: 3.5939, lat: 2.59094)),
|
||||
VelibStation(stationcode: "293R", name: "Test2", capacity: 5, numdocksavailable: 3, numbikesavailable: 2, mechanical: 3, ebike: 1, coordonnees_geo: Coordinates(lon: 5.5939, lat: 3.59094))
|
||||
]
|
||||
|
||||
let testAPI2 = VelibResponse(totalCount: 2, results: [
|
||||
VelibStation(stationcode: "293", name: "Test", capacity: 3, numdocksavailable: 3, numbikesavailable: 3, mechanical: 3, ebike: 1, coordonnees_geo: Coordinates(lon: 3.5939, lat: 2.59094)),
|
||||
VelibStation(stationcode: "293R", name: "Test2", capacity: 5, numdocksavailable: 3, numbikesavailable: 2, mechanical: 3, ebike: 1, coordonnees_geo: Coordinates(lon: 5.5939, lat: 3.59094))
|
||||
])
|
||||
|
||||
|
||||
func fetchVelibStations(completion: @escaping ([VelibStation]?, Error?) -> Void) {
|
||||
guard let url = URL(string: "https://opendata.paris.fr/api/explore/v2.1/catalog/datasets/velib-disponibilite-en-temps-reel/records?select=stationcode,name,capacity,numdocksavailable,numbikesavailable,mechanical,ebike,coordonnees_geo") else {
|
||||
completion(nil, NSError(domain: "fr.louisgallet.velibtracker", code: 1, userInfo: nil))
|
||||
return
|
||||
}
|
||||
|
||||
URLSession.shared.dataTask(with: url) { data, response, error in
|
||||
if let error = error {
|
||||
completion(nil, error)
|
||||
return
|
||||
}
|
||||
|
||||
guard let data = data else {
|
||||
completion(nil, NSError(domain: "fr.louisgallet.velibtracker", code: 2, userInfo: nil))
|
||||
return
|
||||
}
|
||||
let decoder = JSONDecoder()
|
||||
do {
|
||||
let velibResponse = try decoder.decode(VelibResponse.self, from: data)
|
||||
let stations = velibResponse.results
|
||||
// Utilisez la liste des stations dans votre application
|
||||
} catch {
|
||||
print("Erreur lors du décodage JSON : \(error)")
|
||||
}
|
||||
print("Fetched + decoded")
|
||||
}.resume()
|
||||
}
|
||||
|
||||
|
@ -14,4 +14,7 @@ struct velibtrackerApp: App {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
init() {
|
||||
fetchVelibData()
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user