SwiftUI: show iss position on map

This commit is contained in:
John O'Reilly 2021-02-27 10:11:41 +00:00
parent 9b9137dfc5
commit 132969d847
4 changed files with 81 additions and 20 deletions

View file

@ -18,6 +18,7 @@
1ABFB8C723AFF5CE003D807E /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1ABFB8C623AFF5CE003D807E /* Preview Assets.xcassets */; };
1ABFB8CA23AFF5CE003D807E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1ABFB8C823AFF5CE003D807E /* LaunchScreen.storyboard */; };
1AC2439025A1D57700F17D2F /* IssPositionPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AC2438F25A1D57700F17D2F /* IssPositionPublisher.swift */; };
1AD2EC6A25E9984900CCEE81 /* ISSMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AD2EC6925E9984900CCEE81 /* ISSMapView.swift */; };
1E1255057DE614781855FC02 /* libPods-PeopleInSpaceSwiftUI.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 28681F6577A67864E2C2D9B4 /* libPods-PeopleInSpaceSwiftUI.a */; };
/* End PBXBuildFile section */
@ -35,6 +36,7 @@
1ABFB8C923AFF5CE003D807E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
1ABFB8CB23AFF5CE003D807E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
1AC2438F25A1D57700F17D2F /* IssPositionPublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IssPositionPublisher.swift; sourceTree = "<group>"; };
1AD2EC6925E9984900CCEE81 /* ISSMapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ISSMapView.swift; sourceTree = "<group>"; };
28681F6577A67864E2C2D9B4 /* libPods-PeopleInSpaceSwiftUI.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-PeopleInSpaceSwiftUI.a"; sourceTree = BUILT_PRODUCTS_DIR; };
56CD7101BBBC60F561BFB049 /* Pods-PeopleInSpaceSwiftUI.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PeopleInSpaceSwiftUI.release.xcconfig"; path = "Target Support Files/Pods-PeopleInSpaceSwiftUI/Pods-PeopleInSpaceSwiftUI.release.xcconfig"; sourceTree = "<group>"; };
E9A29AFE5FFFB564C509840A /* Pods-PeopleInSpaceSwiftUI.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PeopleInSpaceSwiftUI.debug.xcconfig"; path = "Target Support Files/Pods-PeopleInSpaceSwiftUI/Pods-PeopleInSpaceSwiftUI.debug.xcconfig"; sourceTree = "<group>"; };
@ -102,6 +104,7 @@
1ABD44F923B00008008387E3 /* ViewModel.swift */,
1AA82EEC25052E1E00193051 /* ImageView.swift */,
1AC2438F25A1D57700F17D2F /* IssPositionPublisher.swift */,
1AD2EC6925E9984900CCEE81 /* ISSMapView.swift */,
);
path = PeopleInSpaceSwiftUI;
sourceTree = "<group>";
@ -225,6 +228,7 @@
1AC2439025A1D57700F17D2F /* IssPositionPublisher.swift in Sources */,
1ABFB8BE23AFF5CC003D807E /* AppDelegate.swift in Sources */,
1ABFB8C023AFF5CC003D807E /* SceneDelegate.swift in Sources */,
1AD2EC6A25E9984900CCEE81 /* ISSMapView.swift in Sources */,
1ABD44FA23B00008008387E3 /* ViewModel.swift in Sources */,
1ABFB8C223AFF5CC003D807E /* ContentView.swift in Sources */,
);

View file

@ -1,29 +1,42 @@
import SwiftUI
import Combine
import common
struct ContentView: View {
@StateObject var peopleInSpaceViewModel = PeopleInSpaceViewModel(repository: PeopleInSpaceRepository())
@StateObject var viewModel = PeopleInSpaceViewModel(repository: PeopleInSpaceRepository())
var body: some View {
TabView {
PeopleListView(viewModel: viewModel)
.tabItem {
Label("People", systemImage: "person")
}
ISSMapView(issPosition: $viewModel.issPosition)
.tabItem {
Label("Map", systemImage: "location")
}
}
}
}
struct PeopleListView: View {
@ObservedObject var viewModel: PeopleInSpaceViewModel
var body: some View {
NavigationView {
VStack {
HStack {
Text(peopleInSpaceViewModel.issPositionString)
}
.padding(EdgeInsets(top: 18, leading: 16, bottom: 0, trailing: 16))
VStack {
List(peopleInSpaceViewModel.people, id: \.name) { person in
NavigationLink(destination: PersonDetailsView(peopleInSpaceViewModel: peopleInSpaceViewModel, person: person)) {
PersonView(peopleInSpaceViewModel: self.peopleInSpaceViewModel, person: person)
List(viewModel.people, id: \.name) { person in
NavigationLink(destination: PersonDetailsView(viewModel: viewModel, person: person)) {
PersonView(viewModel: viewModel, person: person)
}
}
.navigationBarTitle(Text("People In Space"))
.onAppear {
self.peopleInSpaceViewModel.startObservingPeopleUpdates()
viewModel.startObservingPeopleUpdates()
}.onDisappear {
self.peopleInSpaceViewModel.stopObservingPeopleUpdates()
viewModel.stopObservingPeopleUpdates()
}
}
}
@ -31,12 +44,12 @@ struct ContentView: View {
}
struct PersonView: View {
var peopleInSpaceViewModel: PeopleInSpaceViewModel
var viewModel: PeopleInSpaceViewModel
var person: Assignment
var body: some View {
HStack {
ImageView(withURL: peopleInSpaceViewModel.getPersonImage(personName: person.name), width: 64, height: 64)
ImageView(withURL: viewModel.getPersonImage(personName: person.name), width: 64, height: 64)
VStack(alignment: .leading) {
Text(person.name).font(.headline)
Text(person.craft).font(.subheadline)
@ -47,7 +60,7 @@ struct PersonView: View {
struct PersonDetailsView: View {
var peopleInSpaceViewModel: PeopleInSpaceViewModel
var viewModel: PeopleInSpaceViewModel
var person: Assignment
var body: some View {
@ -55,9 +68,9 @@ struct PersonDetailsView: View {
VStack(alignment: .center, spacing: 32) {
Text(person.name).font(.title)
ImageView(withURL: peopleInSpaceViewModel.getPersonImage(personName: person.name), width: 240, height: 240)
ImageView(withURL: viewModel.getPersonImage(personName: person.name), width: 240, height: 240)
Text(peopleInSpaceViewModel.getPersonBio(personName: person.name)).font(.body)
Text(viewModel.getPersonBio(personName: person.name)).font(.body)
Spacer()
}
.padding()

View file

@ -0,0 +1,44 @@
import Foundation
import SwiftUI
import MapKit
import common
struct ISSMapView: View {
@Binding var issPosition: IssPosition
var body: some View {
let issCoordinatePosition = CLLocationCoordinate2D(latitude: issPosition.latitude, longitude: issPosition.longitude)
let regionBinding = Binding<MKCoordinateRegion>(
get: {
MKCoordinateRegion(center: issCoordinatePosition, span: MKCoordinateSpan(latitudeDelta: 150, longitudeDelta: 150))
},
set: { _ in }
)
VStack {
Text("\(issPosition.latitude), \(issPosition.longitude)")
Map(coordinateRegion: regionBinding, showsUserLocation: true,
annotationItems: [ Location(coordinate: issCoordinatePosition) ]) { (location) -> MapPin in
MapPin(coordinate: location.coordinate)
}
}
}
}
struct Location: Identifiable {
let id = UUID()
let coordinate: CLLocationCoordinate2D
}
struct MapView: View {
let issPosition: IssPosition
let region: Binding<MKCoordinateRegion>
var body: some View {
Map(coordinateRegion: region, showsUserLocation: true,
annotationItems: [ Location(coordinate: .init(latitude: issPosition.latitude, longitude: issPosition.longitude)) ]) { (location) -> MapPin in
MapPin(coordinate: location.coordinate)
}
}
}

View file

@ -5,7 +5,7 @@ import common
class PeopleInSpaceViewModel: ObservableObject {
@Published var people = [Assignment]()
@Published var issPositionString = ""
@Published var issPosition = IssPosition(latitude: 0, longitude: 0)
private var subscription: AnyCancellable?
@ -14,8 +14,8 @@ class PeopleInSpaceViewModel: ObservableObject {
self.repository = repository
subscription = IssPositionPublisher(repository: repository)
.map { position in String(format: "ISS Position = (%f, %f)", position.latitude, position.longitude ) }
.assign(to: \.issPositionString, on: self)
//.map { position in String(format: "ISS Position = (%f, %f)", position.latitude, position.longitude ) }
.assign(to: \.issPosition, on: self)
}
func startObservingPeopleUpdates() {