diff --git a/Epicentral.xcodeproj/project.pbxproj b/Epicentral.xcodeproj/project.pbxproj index b2d83ae..199d202 100644 --- a/Epicentral.xcodeproj/project.pbxproj +++ b/Epicentral.xcodeproj/project.pbxproj @@ -37,6 +37,7 @@ 06EFE9F32AFAC2AD00351973 /* TestData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06EFE9F22AFAC2AD00351973 /* TestData.swift */; }; 06EFE9F52AFAC3B800351973 /* GeoJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06EFE9F42AFAC3B800351973 /* GeoJSON.swift */; }; 06EFE9F92AFAD6D500351973 /* EarthquakesState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06EFE9F82AFAD6D500351973 /* EarthquakesState.swift */; }; + 06F44F7B2B9A7DEA0024532B /* EarthquakePreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06F44F7A2B9A7DEA0024532B /* EarthquakePreviewView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -91,6 +92,7 @@ 06EFE9F22AFAC2AD00351973 /* TestData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestData.swift; sourceTree = ""; }; 06EFE9F42AFAC3B800351973 /* GeoJSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoJSON.swift; sourceTree = ""; }; 06EFE9F82AFAD6D500351973 /* EarthquakesState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EarthquakesState.swift; sourceTree = ""; }; + 06F44F7A2B9A7DEA0024532B /* EarthquakePreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EarthquakePreviewView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -163,6 +165,7 @@ 068B01A12B0DB2BD0012D86C /* FloatingButtonView */, 06DA01642AFDBB1E0008FE49 /* EarthquakeList */, 06DA015E2AFD91FB0008FE49 /* LoadingIndicator.swift */, + 06F44F7A2B9A7DEA0024532B /* EarthquakePreviewView.swift */, ); path = Components; sourceTree = ""; @@ -454,6 +457,7 @@ 06EFE9F52AFAC3B800351973 /* GeoJSON.swift in Sources */, 06DA01532AFC0DD30008FE49 /* EarthquakeGeometry.swift in Sources */, 068B01A32B0DB5A90012D86C /* FloatingButtonView.swift in Sources */, + 06F44F7B2B9A7DEA0024532B /* EarthquakePreviewView.swift in Sources */, 06EFE9B72AFAB91E00351973 /* EpicentralApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -618,7 +622,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 162; DEVELOPMENT_ASSET_PATHS = "\"Epicentral/Preview Content\""; DEVELOPMENT_TEAM = DUCAN2M87U; ENABLE_PREVIEWS = YES; @@ -634,7 +638,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1; + MARKETING_VERSION = 1.2; PRODUCT_BUNDLE_IDENTIFIER = com.bsakhuja.Epicentral; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -652,7 +656,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 162; DEVELOPMENT_ASSET_PATHS = "\"Epicentral/Preview Content\""; DEVELOPMENT_TEAM = DUCAN2M87U; ENABLE_PREVIEWS = YES; @@ -668,7 +672,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1; + MARKETING_VERSION = 1.2; PRODUCT_BUNDLE_IDENTIFIER = com.bsakhuja.Epicentral; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -685,7 +689,7 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 162; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 17.2; MARKETING_VERSION = 1.0; @@ -704,7 +708,7 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 162; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 17.2; MARKETING_VERSION = 1.0; @@ -722,7 +726,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 162; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.bsakhuja.PlateUITests; @@ -739,7 +743,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 162; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.bsakhuja.PlateUITests; diff --git a/Epicentral/Models/EarthquakeProperties.swift b/Epicentral/Models/EarthquakeProperties.swift index caa2503..06415ba 100644 --- a/Epicentral/Models/EarthquakeProperties.swift +++ b/Epicentral/Models/EarthquakeProperties.swift @@ -21,6 +21,7 @@ struct EarthquakeProperties: Identifiable { var id: String { code } let tsunami: Bool? let title: String + let url: URL? var date: Date { Date(timeIntervalSince1970: time / 1000) @@ -36,6 +37,7 @@ extension EarthquakeProperties: Decodable { case detail case tsunami case title + case url } init(from decoder: Decoder) throws { @@ -47,12 +49,15 @@ extension EarthquakeProperties: Decodable { let rawDetail = try? values.decode(URL.self, forKey: .detail) let rawTsunami = try? values.decode(Bool.self, forKey: .tsunami) let rawTitle = try? values.decode(String.self, forKey: .title) + let rawURL = try? values.decode(String.self, forKey: .url) guard let magnitude = rawMagnitude, let time = rawTime, let code = rawCode, let detail = rawDetail, - let title = rawTitle + let title = rawTitle, + let urlString = rawURL, + let url = URL(string: urlString) else { throw QuakeError.missingData } @@ -64,11 +69,12 @@ extension EarthquakeProperties: Decodable { self.detail = detail self.tsunami = rawTsunami self.title = title + self.url = url } } extension EarthquakeProperties { - static let testEarthquakeProperties = EarthquakeProperties(magnitude: 2.4, place: "10km SSW of Idyllwild, CA", time: 1388620296020, code: "code", detail: nil, tsunami: false, title: "M 1.3 - 10km SSW of Idyllwild, CA") + static let testEarthquakeProperties = EarthquakeProperties(magnitude: 2.4, place: "10km SSW of Idyllwild, CA", time: 1388620296020, code: "code", detail: nil, tsunami: false, title: "M 1.3 - 10km SSW of Idyllwild, CA", url: URL(string: "https://earthquake.usgs.gov/earthquakes/eventpage/tx2024eqpe")) } diff --git a/Epicentral/Views/Components/EarthquakePreviewView.swift b/Epicentral/Views/Components/EarthquakePreviewView.swift new file mode 100644 index 0000000..bc3290c --- /dev/null +++ b/Epicentral/Views/Components/EarthquakePreviewView.swift @@ -0,0 +1,54 @@ +// +// EarthquakePreviewView.swift +// Epicentral +// +// Created by Brian Sakhuja on 3/7/24. +// + +import SwiftUI + +struct EarthquakePreviewView: View { + + @State private var isShowingDetails: Bool = false + + let earthquake: Earthquake + + var body: some View { + VStack { + HStack { + Text(earthquake.properties.title) + .font(.headline) + Spacer() + } + HStack { + Text("Magnitude") + Spacer() + Text(preciseRound(earthquake.properties.magnitude, precision: .hundredths)) + } + HStack { + Text("Date & Time") + Spacer() + Text(earthquake.properties.date.formatted(.dateTime)) + } + if let tsunami = earthquake.properties.tsunami { + HStack { + Text("Tsunami warning") + Spacer() + Text(tsunami ? "Yes" : "No") + } + } + Button("Details") { + isShowingDetails = true + } + } + .padding() + .sheet(isPresented: $isShowingDetails) { + EarthquakeDetailView(earthquake: earthquake) + .presentationDragIndicator(.visible) + } + } +} + +#Preview { + EarthquakePreviewView(earthquake: Earthquake.testEarthquake) +} diff --git a/Epicentral/Views/Screens/EarthquakeDetailView.swift b/Epicentral/Views/Screens/EarthquakeDetailView.swift index a434dbf..369c2e7 100644 --- a/Epicentral/Views/Screens/EarthquakeDetailView.swift +++ b/Epicentral/Views/Screens/EarthquakeDetailView.swift @@ -7,6 +7,7 @@ import SwiftUI import MapKit +import WebKit struct EarthquakeDetailView: View { @@ -45,7 +46,12 @@ struct EarthquakeDetailView: View { Text(tsunami ? "Yes" : "No") } } - + if let url = earthquake.properties.url { + HStack { + Link("View on USGS", destination: url) + Spacer() + } + } } diff --git a/Epicentral/Views/Screens/EarthquakesMapView.swift b/Epicentral/Views/Screens/EarthquakesMapView.swift index 4a1b9f4..bdb72d7 100644 --- a/Epicentral/Views/Screens/EarthquakesMapView.swift +++ b/Epicentral/Views/Screens/EarthquakesMapView.swift @@ -19,6 +19,7 @@ struct EarthquakesMapView: View { longitudinalMeters: 100_000) @State private var selectedEarthquake: Earthquake? + @State private var showingEarthquakePreview = false var filteredEarthquakes: [Earthquake]? { state.earthquakes?.filter { @@ -37,16 +38,23 @@ struct EarthquakesMapView: View { .tag(result.id) } } - // TODO/ make a detail view below then have button go to detail view -// .safeAreaInset(edge: .bottom) { -// if let selectedEarthquake { -// Text(selectedEarthquake.id) -// .frame(height: 128) -// .clipShape(RoundedRectangle(cornerRadius: 10)) -// .padding([.top, .horizontal]) -// -// } -// } + .onChange(of: selectedEarthquake) { + showingEarthquakePreview = selectedEarthquake != nil + } + .onChange(of: showingEarthquakePreview) { + if !showingEarthquakePreview { + selectedEarthquake = nil + } + } + .animation(.easeInOut(duration: 0.3), value: selectedEarthquake) + .sheet(isPresented: $showingEarthquakePreview, content: { + if let earthquake = selectedEarthquake { + EarthquakePreviewView(earthquake: earthquake) + .presentationDetents([.fraction(0.25)]) + .presentationDragIndicator(.visible) + } + + }) } else { VStack { Spacer()