News API : https://newsapi.org/
ContentView.swift
// // ContentView.swift // SwiftUIProject // // Created by Cairocoders // import SwiftUI struct ContentView: View { var body: some View { NewsFeedView() } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } struct NewsFeedView: View { @ObservedObject var newsFeed = NewsFeed() var body: some View { NavigationView { List(newsFeed) { (article: NewsListItem) in NavigationLink(destination: NewsListItemView(article: article)) { NewsListItemListView(article: article) .onAppear { self.newsFeed.loadMoreArticles(currentItem: article) } } } .navigationBarTitle("Apple News") } } } struct NewsListItemView: View { var article: NewsListItem var body: some View { VStack { UrlWebView(urlToDisplay: URL(string: article.url)!) .edgesIgnoringSafeArea(.all) .navigationBarTitle(article.title) } } } struct NewsListItemListView: View { var article: NewsListItem var body: some View { HStack { VStack(alignment: .leading) { Text("\(article.title)") .font(.headline) Text("\(article.author ?? "No Author")") .font(.subheadline) } } } }NewsFeedModels.swift
// // NewsFeedModels.swift // SwiftUIProject // // Created by Cairocoders // import Foundation class NewsFeed: ObservableObject, RandomAccessCollection { typealias Element = NewsListItem @Published var newsListItems = [NewsListItem]() var startIndex: Int { newsListItems.startIndex } var endIndex: Int { newsListItems.endIndex } var loadStatus = LoadStatus.ready(nextPage: 1) var urlBase = "https://newsapi.org/v2/everything?q=apple&sortBy=popularity&apiKey=55c250f06e1144c29a3ec4d2530adbe5&language=en&page=" init() { loadMoreArticles() } subscript(position: Int) -> NewsListItem { return newsListItems[position] } func loadMoreArticles(currentItem: NewsListItem? = nil) { if !shouldLoadMoreData(currentItem: currentItem) { return } guard case let .ready(page) = loadStatus else { return } loadStatus = .loading(page: page) let urlString = "\(urlBase)\(page)" let url = URL(string: urlString)! let task = URLSession.shared.dataTask(with: url, completionHandler: parseArticlesFromResponse(data:response:error:)) task.resume() } func shouldLoadMoreData(currentItem: NewsListItem? = nil) -> Bool { guard let currentItem = currentItem else { return true } for n in (newsListItems.count - 4)...(newsListItems.count-1) { if n >= 0 && currentItem.uuid == newsListItems[n].uuid { return true } } return false } func parseArticlesFromResponse(data: Data?, response: URLResponse?, error: Error?) { guard error == nil else { print("Error: \(error!)") loadStatus = .parseError return } guard let data = data else { print("No data found") loadStatus = .parseError return } let newArticles = parseArticlesFromData(data: data) DispatchQueue.main.async { self.newsListItems.append(contentsOf: newArticles) if newArticles.count == 0 { self.loadStatus = .done } else { guard case let .loading(page) = self.loadStatus else { fatalError("loadSatus is in a bad state") } self.loadStatus = .ready(nextPage: page + 1) } } } func parseArticlesFromData(data: Data) -> [NewsListItem] { var response: NewsApiResponse do { response = try JSONDecoder().decode(NewsApiResponse.self, from: data) } catch { print("Error parsing the JSON: \(error)") return [] } if response.status != "ok" { print("Status is not ok: \(response.status)") return [] } return response.articles ?? [] } enum LoadStatus { case ready (nextPage: Int) case loading (page: Int) case parseError case done } } class NewsApiResponse: Codable { var status: String var articles: [NewsListItem]? } class NewsListItem: Identifiable, Codable { var uuid = UUID() var author: String? var title: String var url: String enum CodingKeys: String, CodingKey { case author, title, url } }UrlWebView.swift
// // UrlWebView.swift // SwiftUIProject // // Created by Cairocoders // import SwiftUI import WebKit struct UrlWebView: UIViewRepresentable { typealias UIViewType = WKWebView var urlToDisplay: URL func makeUIView(context: Context) -> WKWebView { let webView = WKWebView() webView.load(URLRequest(url: urlToDisplay)) return webView } func updateUIView(_ uiView: WKWebView, context: Context) { } }