github.com/ParkJinhui/Sample-IOS-Covid
ParkJinhui/Sample-IOS-Covid
Contribute to ParkJinhui/Sample-IOS-Covid development by creating an account on GitHub.
github.com
RapidAPI - The Next Generation API Platform
Use RapidAPI to Find, Connect, & Share 1000s of APIs using our Multi-cloud platform. Improve Developer Experience with API Design, Testing, Monitoring, & More!
rapidapi.com
Podfile
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
target 'Covid' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# Pods for Covid
pod 'Alamofire', '~> 5.0'
pod 'SwiftyJSON', '~> 4.0'
end
CovidApp
//
// CovidApp.swift
// Covid
//
// Created by user on 2021/01/27.
//
import SwiftUI
@main
struct CovidApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
ContentView
//
// ContentView.swift
// CoronaStats
//
// Created by user on 2021/01/27.
//
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
RecentView()
.tabItem {
Tab(imageName: "chart.bar", text: "Recent")
}
.tag(0)
MapContainerView()
.edgesIgnoringSafeArea(.vertical)
.tabItem {
Tab(imageName: "map", text: "Map")
}
.tag(1)
}
}
}
private struct Tab: View {
let imageName: String
let text: String
var body: some View {
VStack {
Image(systemName: imageName)
Text(text)
}
}
}
CountryDetailView
//
// CountryDetailView.swift
// CoronaStats
//
// Created by user on 2021/01/27.
//
import SwiftUI
struct CountryDetailView: View {
var countryData: CountryData
var body: some View {
VStack {
VStack {
CountryDetailRow(number: countryData.confirmed.formatNumber(), name: "Confirmed")
.padding(.top)
CountryDetailRow(number: countryData.critical.formatNumber(), name: "Critical", color: .yellow)
CountryDetailRow(number: countryData.deaths.formatNumber(), name: "Deaths", color: .red)
CountryDetailRow(number: String(format: "%.2f", countryData.fatalityRate), name: "Death%", color: .red)
CountryDetailRow(number: countryData.recovered.formatNumber(), name: "Recovered", color: .green)
CountryDetailRow(number: String(format: "%.2f", countryData.recoveredRate), name: "Recovered%", color: .green)
}
.background(Color("cardBackgroundGray"))
.cornerRadius(8)
.padding()
Spacer()
}
.padding(.top, 50)
.navigationBarTitle(countryData.country)
}
}
struct CountryDetailView_Previews: PreviewProvider {
static var previews: some View {
CountryDetailView(countryData: testCountryData)
}
}
Extension
//
// Extension.swift
// CoronaStats
//
// Created by user on 2021/01/27.
//
import Foundation
extension Int {
func formatNumber() -> String {
let formatter = NumberFormatter()
formatter.groupingSeparator = ","
formatter.numberStyle = .decimal
return formatter.string(from: NSNumber(value: self))!
}
}
extension Int64 {
func formatNumber() -> String {
let formatter = NumberFormatter()
formatter.groupingSeparator = ","
formatter.numberStyle = .decimal
return formatter.string(from: NSNumber(value: self))!
}
}
MapContainerView
//
// MapContainerView.swift
// CoronaStats
//
// Created by user on 2021/01/27.
//
import SwiftUI
struct MapContainerView: View {
@ObservedObject var covidFetch = CovidFetchRequest()
var body: some View {
MapView(countryData: $covidFetch.allCountries)
}
}
struct MapContainerView_Previews: PreviewProvider {
static var previews: some View {
MapContainerView()
}
}
Model
//
// Model.swift
// CoronaStats
//
// Created by user on 2021/01/27.
//
import Foundation
struct TotalData {
let confirmed: Int
let critical: Int
let deaths: Int
let recovered: Int
var fatalityRate: Double {
return (100.00 * Double(deaths)) / Double(confirmed)
}
var recoveredRate: Double {
return (100.00 * Double(recovered)) / Double(confirmed)
}
}
struct CountryData {
let country: String
let confirmed: Int64
let critical: Int64
let deaths: Int64
let recovered: Int64
let longitude: Double
let latitude: Double
var fatalityRate: Double {
return (100.00 * Double(deaths)) / Double(confirmed)
}
var recoveredRate: Double {
return (100.00 * Double(recovered)) / Double(confirmed)
}
}
let testTotalData = TotalData(confirmed: 200, critical: 100, deaths: 20, recovered: 50)
let testCountryData = CountryData(country: "Test", confirmed: 500, critical: 300, deaths: 200, recovered: 100, longitude: 0.0, latitude: 0.0)
CovidFetchRequest
//
// CovidFetchRequest.swift
// CoronaStats
//
// Created by user on 2021/01/27.
//
import Foundation
import Alamofire
import SwiftyJSON
class CovidFetchRequest: ObservableObject {
@Published var allCountries: [CountryData] = []
@Published var totalData: TotalData = testTotalData
let headers: HTTPHeaders = [
"x-rapidapi-host": "covid-19-data.p.rapidapi.com",
"x-rapidapi-key": ""
]
init() {
getAllCountries()
getCurrentTotal()
}
func getCurrentTotal() {
AF.request("https://covid-19-data.p.rapidapi.com/totals?format=undefined", headers: headers).responseJSON { response in
let result = response.data
if result != nil {
let json = JSON(result!)
// print(json)
let confirmed = json[0]["confirmed"].intValue
let deaths = json[0]["deaths"].intValue
let recovered = json[0]["recovered"].intValue
let critical = json[0]["critical"].intValue
self.totalData = TotalData(confirmed: confirmed, critical: critical, deaths: deaths, recovered: recovered)
} else {
self.totalData = testTotalData
}
}
}
func getAllCountries() {
AF.request("https://covid-19-data.p.rapidapi.com/country/all?format=undefined", headers: headers).responseJSON { response in
let result = response.value
var allCount: [CountryData] = []
if result != nil {
let dataDictionary = result as! [Dictionary<String, AnyObject>]
for countryData in dataDictionary {
let country = countryData["country"] as? String ?? "Error"
let longitude = countryData["longitude"] as? Double ?? 0.0
let latitude = countryData["latitude"] as? Double ?? 0.0
let confirmed = countryData["confirmed"] as? Int64 ?? 0
let deaths = countryData["deaths"] as? Int64 ?? 0
let recovered = countryData["recovered"] as? Int64 ?? 0
let critical = countryData["critical"] as? Int64 ?? 0
let countryObject = CountryData(country: country, confirmed: confirmed, critical: critical, deaths: deaths, recovered: recovered, longitude: longitude, latitude: latitude)
allCount.append(countryObject)
}
}
self.allCountries = allCount.sorted(by: { $0.confirmed > $1.confirmed })
}
}
}
RecentView
//
// RecentView.swift
// CoronaStats
//
// Created by user on 2021/01/27.
//
import SwiftUI
struct RecentView: View {
@ObservedObject var covidFetch = CovidFetchRequest()
@State var searchText = ""
@State var isSearchVisible = false
var body: some View {
NavigationView {
VStack {
if isSearchVisible {
SearchView(searchText: $searchText)
}
TotalDataView(totalData: covidFetch.totalData)
ListHeaderView()
List {
ForEach(covidFetch.allCountries.filter {
self.searchText.isEmpty ? true : $0.country.lowercased().contains(self.searchText.lowercased())
}, id: \.country) { countryData in
NavigationLink(destination: CountryDetailView(countryData: countryData)) {
CountryDataRowView(countryData: countryData)
}
}
}
}//End of VStack
.navigationBarTitle("Recent Data", displayMode: .inline)
.navigationBarItems(trailing:
Button(action: {
self.isSearchVisible.toggle()
if !self.isSearchVisible {
self.searchText = ""
}
}, label: {
Image(systemName: "magnifyingglass")
})
)
}//End of Navigation view
}
}
struct RecentView_Previews: PreviewProvider {
static var previews: some View {
RecentView()
}
}
SearchView
//
// SearchView.swift
// CoronaStats
//
// Created by user on 2021/01/27.
//
import SwiftUI
struct SearchView: View {
@Binding var searchText: String
var body: some View {
HStack {
TextField("Country...", text: $searchText)
.padding()
}
.frame(height: 50)
.background(Color("cardBackgroundGray"))
}
}
MapView
//
// MapView.swift
// CoronaStats
//
// Created by user on 2021/01/27.
//
import SwiftUI
import UIKit
import MapKit
struct MapView: UIViewRepresentable {
@Binding var countryData: [CountryData]
func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<MapView>) {
var allAnnotations: [CoronaCaseAnnotation] = []
for data in countryData {
let title = data.country + "\n Confirmed " + data.confirmed.formatNumber() + "\n Death " + data.deaths.formatNumber()
let coordinate = CLLocationCoordinate2D(latitude: data.latitude, longitude: data.longitude)
allAnnotations.append(CoronaCaseAnnotation(title: title, coordinate: coordinate))
}
uiView.annotations.forEach { uiView.removeAnnotation($0) }
uiView.addAnnotations(allAnnotations)
}
func makeUIView(context: UIViewRepresentableContext<MapView>) -> MKMapView {
return MKMapView()
}
}
class CoronaCaseAnnotation: NSObject, MKAnnotation {
let title: String?
let coordinate: CLLocationCoordinate2D
init(title: String?, coordinate: CLLocationCoordinate2D) {
self.title = title
self.coordinate = coordinate
}
}
CountryDetailRow
//
// CountryDetailRow.swift
// CoronaStats
//
// Created by user on 2021/01/27.
//
import SwiftUI
struct CountryDetailRow: View {
var number: String = "Err"
var name: String = "Confirmed"
var color: Color = .primary
var body: some View {
VStack {
HStack {
Text(self.name)
.font(.body)
.padding(5)
Spacer()
Text(self.number)
.font(.subheadline)
.padding(5)
.foregroundColor(color)
}
Divider()
}
.padding(.leading)
.padding(.trailing)
}
}
struct CountryDetailRow_Previews: PreviewProvider {
static var previews: some View {
CountryDetailRow()
}
}
CountryDataRowView
//
// CountryDataRowView.swift
// CoronaStats
//
// Created by user on 2021/01/27.
//
import SwiftUI
struct CountryDataRowView: View {
var countryData: CountryData
var body: some View {
HStack {
Text(countryData.country)
.fontWeight(.medium)
.font(.subheadline)
.lineLimit(2)
.frame(width: 110, alignment: .leading)
Spacer()
Text(countryData.confirmed.formatNumber())
.font(.subheadline)
.frame(height: 40)
.padding(.leading, 5)
Spacer()
Text(countryData.deaths.formatNumber())
.frame(width: 50, height: 40, alignment: .center)
.font(.subheadline)
.foregroundColor(.red)
.padding(.leading, 5)
Spacer()
Text(countryData.recovered.formatNumber())
.frame(width: 50, height: 40, alignment: .center)
.font(.subheadline)
.foregroundColor(.green)
}
}
}
struct CountryDataRowView_Previews: PreviewProvider {
static var previews: some View {
CountryDataRowView(countryData: testCountryData)
}
}
TotalDataCard
//
// TotalDataCard.swift
// CoronaStats
//
// Created by user on 2021/01/27.
//
import SwiftUI
struct TotalDataCard: View {
var number: String = "Err"
var name: String = "Confirmed"
var color: Color = .primary
var body: some View {
GeometryReader { geometry in
VStack {
Text(self.number)
.font(.subheadline)
.padding(5)
.foregroundColor(self.color)
Text(self.name)
.font(.body)
.padding(5)
.foregroundColor(self.color)
}//End of VStack
.frame(width: geometry.size.width, height: 80, alignment: .center)
.background(Color("cardBackgroundGray"))
.cornerRadius(8.0)
}//End of Geometry
}
}
struct TotalDataCard_Previews: PreviewProvider {
static var previews: some View {
TotalDataCard()
}
}
ListHeaderView
//
// ListHeaderView.swift
// CoronaStats
//
// Created by user on 2021/01/27.
//
import SwiftUI
struct ListHeaderView: View {
var body: some View {
HStack {
Text("Country")
.fontWeight(.bold)
.font(.subheadline)
.frame(width: 110, alignment: .leading)
.padding(.leading, 15)
Spacer()
Text("Conf.")
.fontWeight(.bold)
.font(.subheadline)
.frame(height: 40)
.padding(.leading, 5)
Spacer()
Text("Death")
.fontWeight(.bold)
.font(.subheadline)
.frame(height: 40)
.padding(.leading, 5)
Spacer()
Text("Recover")
.fontWeight(.bold)
.font(.subheadline)
.frame(height: 40)
.padding(.trailing, 15)
}
.background(Color("cardBackgroundGray"))
}
}
struct ListHeaderView_Previews: PreviewProvider {
static var previews: some View {
ListHeaderView()
}
}
TotalDataView
//
// TotalDataView.swift
// CoronaStats
//
// Created by user on 2021/01/27.
//
import SwiftUI
struct TotalDataView: View {
var totalData: TotalData
var body: some View {
VStack {
HStack {
TotalDataCard(number: totalData.confirmed.formatNumber(), name: "Confirmed")
TotalDataCard(number: totalData.critical.formatNumber(), name: "Critical", color: .yellow)
TotalDataCard(number: totalData.deaths.formatNumber(), name: "Deaths", color: .red)
}
HStack {
TotalDataCard(number: String(format: "%.2f", totalData.fatalityRate), name: "Death %", color: .red)
TotalDataCard(number: totalData.recovered.formatNumber(), name: "Recovered", color: .green)
TotalDataCard(number: String(format: "%.2f", totalData.recoveredRate), name: "Recovery%", color: .green)
}
} //End of Vstack
.frame(height: 170)
.padding(10)
}
}
struct TotalDataView_Previews: PreviewProvider {
static var previews: some View {
TotalDataView(totalData: testTotalData)
}
}