Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions SampleAppSwiftUI/Configs/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ final class Configuration: ConfigurationProtocol {
let key: String? = try? self.value(for: "personal_api")
guard let key, !key.isEmpty else {
/// Get your API key from https://www.cryptocompare.com/
#warning("Please Enter an API Key")
return ""
return "fee600f44d9b682844543c4b6d0eb5715228f8ca6ac9ba8a87aff4432f1f3fe0"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can delete this key and put warning again

}
return key
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// CoinNewsDataSource.swift
// SampleAppSwiftUI
//
// Created by Meryem Şahin on 20.07.2023.
//

import Foundation

protocol CoinNewsRemoteDataSourceProtocol {
func getCoinNews(coinCode: String) async throws -> CoinNewsResponse
}

class CoinNewsRemoteDataSource: CoinNewsRemoteDataSourceProtocol {
let coinNewsService: CoinNewsServiceProtocol

init(coinNewsService: CoinNewsServiceProtocol = WebServiceProvider.shared.coinNewsService) {
self.coinNewsService = coinNewsService
}

func getCoinNews(coinCode: String) async throws -> CoinNewsResponse {
try await coinNewsService.coinNewsRequest(coinCode: coinCode)
}
}
39 changes: 39 additions & 0 deletions SampleAppSwiftUI/Network/ResponseModels/CoinNewsResponse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// CoinNewsResponse.swift
// SampleAppSwiftUI
//
// Created by Meryem Şahin on 20.07.2023.
//

import Foundation

struct CoinNewsResponse: Codable, Hashable, Identifiable {
var id = UUID()
let type: Int
let message: String
let data: [CoinNewData]?
let hasWarning: Bool

enum CodingKeys: String, CodingKey {
case type = "Type"
case message = "Message"
case data = "Data"
case hasWarning = "HasWarning"
}
}

// MARK: - Datum
struct CoinNewData: Codable, Hashable, Identifiable {
let id: String
let imageurl: String
let title: String
let url: String
let body: String
let source: String

enum CodingKeys: String, CodingKey {
case id
case imageurl, title, url, body
case source
}
}
24 changes: 24 additions & 0 deletions SampleAppSwiftUI/Network/UseCases/CoinNewsUseCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// CoinNewsUseCase.swift
// SampleAppSwiftUI
//
// Created by Meryem Şahin on 20.07.2023.
//

import Foundation

protocol CoinNewsUseCaseProtocol {
func getCoinNews(coinCode: String) async throws -> CoinNewsResponse
}

class CoinNewsUseCase: CoinNewsUseCaseProtocol {
let coinNewsRepository: CoinNewsRepositoryProtocol

init(coinNewsRepository: CoinNewsRepositoryProtocol = CoinNewsRepository()) {
self.coinNewsRepository = coinNewsRepository
}

func getCoinNews(coinCode: String) async throws -> CoinNewsResponse {
try await coinNewsRepository.getCoinNews(coinCode: coinCode)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// CoinNewsRepository.swift
// SampleAppSwiftUI
//
// Created by Meryem Şahin on 20.07.2023.
//

import Foundation

protocol CoinNewsRepositoryProtocol {
func getCoinNews(coinCode: String) async throws -> CoinNewsResponse
}

class CoinNewsRepository: CoinNewsRepositoryProtocol {
let coinNewsRemoteDataSource: CoinNewsRemoteDataSourceProtocol

init(coinNewsRemoteDataSource: CoinNewsRemoteDataSourceProtocol = CoinNewsRemoteDataSource()) {
self.coinNewsRemoteDataSource = coinNewsRemoteDataSource
}

func getCoinNews(coinCode: String) async throws -> CoinNewsResponse {
try await coinNewsRemoteDataSource.getCoinNews(coinCode: coinCode)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// CoinNewsService.swift
// SampleAppSwiftUI
//
// Created by Meryem Şahin on 20.07.2023.
//

import Foundation

protocol CoinNewsServiceProtocol {
func coinNewsRequest(coinCode: String) async throws -> CoinNewsResponse
}

final class CoinNewsService: CoinNewsServiceProtocol, BaseServiceProtocol {
typealias Endpoint = CoinNewsServiceEndpoint

var networkLoader: NetworkLoaderProtocol

init(networkLoader: NetworkLoaderProtocol = NetworkLoaderProvider.shared.networkLoader) {
self.networkLoader = networkLoader
}

func coinNewsRequest(coinCode: String) async throws -> CoinNewsResponse {
let urlString = build(endpoint: .coinNews(coinCode: coinCode))
return try await request(with: RequestObject(url: urlString), responseModel: CoinNewsResponse.self)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// CoinNewsServiceEndpoint.swift
// SampleAppSwiftUI
//
// Created by Meryem Şahin on 20.07.2023.
//

import Foundation

enum CoinNewsServiceEndpoint: TargetEndpointProtocol {

case coinNews(coinCode: String)

private struct Constants {
static let coinNewsEndpoint = "v2/news/?categories=%@&api_key=%@"
}

var path: String {
switch self {
case .coinNews(coinCode: let coinCode):
return BaseEndpoint.base.path + String(format: Constants.coinNewsEndpoint, coinCode, Configuration.coinApiKey)
}
}
}
2 changes: 2 additions & 0 deletions SampleAppSwiftUI/Network/WebServices/WebServiceProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ class WebServiceProvider {
let exampleService: ExampleServiceProtocol
let allCoinService: AllCoinServiceProtocol
let coinPriceHistoryService: CoinPriceHistoryServiceProtocol
let coinNewsService: CoinNewsServiceProtocol

private init() {
exampleService = ExampleService()
allCoinService = AllCoinService()
coinPriceHistoryService = CoinPriceHistoryService()
coinNewsService = CoinNewsService()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ internal enum Resources {
internal static let binance = ImageAsset(name: "binance")
internal static let btc = ImageAsset(name: "btc")
internal static let defaultCoin = ImageAsset(name: "default-coin")
internal static let worldNews = ImageAsset(name: "world-news")
}
}
// swiftlint:enable identifier_name line_length nesting type_body_length type_name
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "world-news.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
50 changes: 47 additions & 3 deletions SampleAppSwiftUI/Scenes/Home/Coin/Detail/CoinDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,56 @@ struct CoinDetailView: View {
}
}
}
.frame(minHeight: 300)
.frame(minHeight: 250)
.cornerRadius(Dimensions.CornerRadius.default)
}
.padding(.horizontal, Paddings.side)
.padding(.vertical, Paddings.CoinDetailView.top)
NavigationView {
VStack {
if let newsModel = viewModel.coinNewsDataModel {
List {
Section("News") {
ForEach(newsModel.prefix(5)) { model in
NavigationLink(destination: WebView(url: URL(string: model.url))) {
HStack {
AsyncImage(url: URL(string: model.imageurl)) { phase in
if let image = phase.image {
image.resizable()
} else {
Resources.Images.worldNews.swiftUIImage.resizable()
}
}
.scaledToFit()
.clipShape(Circle())
.frame(width: Dimensions.imageWidth, height: Dimensions.imageHeight)
Text(model.title)
.limitedCharacterCount(60, model.title, "...")
}
}
}
}
}
.scrollDisabled(true)
.listStyle(.inset)
}
}
}
Button {
} label: {
NavigationLink(destination: CoinNewsListView(coinData: viewModel.coinData)) {
Text("View More")
.frame(width: UIScreen.main.bounds.size.width - 70)
.font(.system(size: 18))
.padding()
.foregroundColor(Color.searchIcon)
.overlay(
RoundedRectangle(cornerRadius: 25)
.stroke(Color.lightGray, lineWidth: 2)
)
}
}.background(Color.lightGray)
.cornerRadius(25)
Spacer()
}
.navigationTitle(Text(verbatim: viewModel.coinData.coinInfo?.title ?? ""))
.navigationBarTitleDisplayMode(.inline)
Expand All @@ -101,7 +146,6 @@ struct CoinDetailView_Previews: PreviewProvider {
static var previews: some View {
Group {
CoinDetailView(coinData: CoinData.demo)

NavigationView {
CoinDetailView(coinData: CoinData.demo)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class CoinDetailViewModel: ObservableObject {
}
}
@Published private(set) var coinPriceHistoryChartDataModel: CoinPriceHistoryChartDataModel?
@Published private(set) var coinNewsDataModel: [CoinNewData]?
@Published private(set) var isLoading: Bool = false
@Published var priceChartSelectedXDateText: String = ""

Expand All @@ -24,15 +25,18 @@ class CoinDetailViewModel: ObservableObject {
}

private let coinPriceHistoryUseCase: CoinPriceHistoryUseCaseProtocol
private let coinNewsUseCase: CoinNewsUseCaseProtocol

init(coinData: CoinData, coinPriceHistoryUseCase: CoinPriceHistoryUseCaseProtocol = CoinPriceHistoryUseCase()) {
init(coinData: CoinData, coinPriceHistoryUseCase: CoinPriceHistoryUseCaseProtocol = CoinPriceHistoryUseCase(), coinNewsUseCase: CoinNewsUseCaseProtocol = CoinNewsUseCase()) {
self.coinData = coinData
self.coinPriceHistoryUseCase = coinPriceHistoryUseCase
self.coinNewsUseCase = coinNewsUseCase
}

func onAppear() {
checkIsCoinFavorite()
fetchCoinPriceHistory(forSelectedRange: chartHistoryRangeSelection)
fetchCoinNews()
}

func getIconURL() -> URL? {
Expand Down Expand Up @@ -90,4 +94,19 @@ class CoinDetailViewModel: ObservableObject {
}
}
}

func fetchCoinNews() {
guard let coinCode = coinData.coinInfo?.code else { return }

Task {
var response: CoinNewsResponse?
response = try? await coinNewsUseCase.getCoinNews(coinCode: coinCode)

guard let response = response, let coinNewData = response.data else { return }
DispatchQueue.main.async {
self.coinNewsDataModel = coinNewData
print(coinNewData)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// CoinNewsListView.swift
// SampleAppSwiftUI
//
// Created by Meryem Şahin on 25.07.2023.
//

import SwiftUI

struct CoinNewsListView: View {
@StateObject private var viewModel: CoinDetailViewModel

init(coinData: CoinData) {
_viewModel = StateObject(wrappedValue: CoinDetailViewModel(coinData: coinData))
}
var body: some View {
VStack {
ScrollView {
NavigationView {
if let newsModel = viewModel.coinNewsDataModel {
List {
ForEach(newsModel) { model in
NavigationLink(destination: WebView(url: URL(string: model.url))) {
HStack {
AsyncImage(url: URL(string: model.imageurl)) { phase in
if let image = phase.image {
image.resizable()
} else {
Resources.Images.worldNews.swiftUIImage.resizable()
}
}
.scaledToFit()
.clipShape(Circle())
.frame(width: Dimensions.imageWidth, height: Dimensions.imageHeight)
Text(model.title)
}
}
}
}
.listStyle(.inset)
}
}.frame(height: UIScreen.main.bounds.height)
.navigationTitle("News")
.navigationBarTitleDisplayMode(.inline)
.navigationViewStyle(.automatic)
}
}
.onAppear {
viewModel.onAppear()
}
}
}

struct CoinNewsListView_Previews: PreviewProvider {
static var previews: some View {
CoinNewsListView(coinData: CoinData.demo)
}
}
Loading