Skip to content

Commit

Permalink
Merge pull request #109 from nimblehq/release/0.8.0
Browse files Browse the repository at this point in the history
Release - 0.8.0
  • Loading branch information
Thieurom authored Jan 27, 2023
2 parents a7f28bc + 10b80da commit 7e3ecc4
Show file tree
Hide file tree
Showing 16 changed files with 210 additions and 44 deletions.
12 changes: 4 additions & 8 deletions CryptoPrices.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
objects = {

/* Begin PBXBuildFile section */
1C3B441229504D8200AFCD81 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C3B441129504D8200AFCD81 /* AppState.swift */; };
1C3B441429504DDD00AFCD81 /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C3B441329504DDD00AFCD81 /* AppCoordinator.swift */; };
1C3B441D2952B34D00AFCD81 /* Wormholy in Frameworks */ = {isa = PBXBuildFile; productRef = 1C3B441C2952B34D00AFCD81 /* Wormholy */; };
246DD0582953FCA0002BB9B9 /* Factory in Frameworks */ = {isa = PBXBuildFile; productRef = 246DD0572953FCA0002BB9B9 /* Factory */; };
Expand Down Expand Up @@ -52,7 +51,6 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
1C3B441129504D8200AFCD81 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = "<group>"; };
1C3B441329504DDD00AFCD81 /* AppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCoordinator.swift; sourceTree = "<group>"; };
249752BB29418C64003C6238 /* MyCoin */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = MyCoin; path = CryptoPrices/Sources/MyCoin; sourceTree = "<group>"; };
24A9D1A72952C54E007DBBCB /* Container+Injection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Container+Injection.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -118,7 +116,6 @@
isa = PBXGroup;
children = (
4D0A1DA129349D660038624D /* AppView.swift */,
1C3B441129504D8200AFCD81 /* AppState.swift */,
1C3B441329504DDD00AFCD81 /* AppCoordinator.swift */,
);
path = AppView;
Expand Down Expand Up @@ -429,7 +426,6 @@
buildActionMask = 2147483647;
files = (
1C3B441429504DDD00AFCD81 /* AppCoordinator.swift in Sources */,
1C3B441229504D8200AFCD81 /* AppState.swift in Sources */,
4D0A1DA229349D660038624D /* AppView.swift in Sources */,
24A9D1A82952C54E007DBBCB /* Container+Injection.swift in Sources */,
4D0A1DA029349D660038624D /* CryptoPricesApp.swift in Sources */,
Expand Down Expand Up @@ -551,7 +547,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.7.0;
MARKETING_VERSION = 0.8.0;
PRODUCT_BUNDLE_IDENTIFIER = "co.nimblehq.crypto-prices.staging";
PRODUCT_MODULE_NAME = CryptoPrices;
PRODUCT_NAME = "$(TARGET_NAME) Staging";
Expand Down Expand Up @@ -682,7 +678,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.7.0;
MARKETING_VERSION = 0.8.0;
PRODUCT_BUNDLE_IDENTIFIER = "co.nimblehq.crypto-prices.staging";
PRODUCT_MODULE_NAME = CryptoPrices;
PRODUCT_NAME = "$(TARGET_NAME) Staging";
Expand Down Expand Up @@ -871,7 +867,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.7.0;
MARKETING_VERSION = 0.8.0;
PRODUCT_BUNDLE_IDENTIFIER = "co.nimblehq.crypto-prices";
PRODUCT_MODULE_NAME = CryptoPrices;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand Down Expand Up @@ -908,7 +904,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 0.7.0;
MARKETING_VERSION = 0.8.0;
PRODUCT_BUNDLE_IDENTIFIER = "co.nimblehq.crypto-prices";
PRODUCT_MODULE_NAME = CryptoPrices;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"images" : [
{
"filename" : "app-icon.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 0 additions & 15 deletions CryptoPrices/Sources/App/AppView/AppState.swift

This file was deleted.

13 changes: 6 additions & 7 deletions CryptoPrices/Sources/App/AppView/AppView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,21 @@ import SwiftUI
struct AppView: View {

@StateObject private var appCoordinator: AppCoordinator = .init()
@Injected(Container.homeViewModel) private var homeViewModel
@Injected(Container.myCoinViewModel) private var myCoinViewModel
@State private var showingMyCoin = false

var body: some View {
NavigationView {
ZStack {
HomeView(viewModel: homeViewModel)
HomeView(viewModel: Container.homeViewModel())
.environmentObject(appCoordinator.homeState)

NavigationLink("", isActive: $showingMyCoin) {
if let myCoinState = appCoordinator.myCoinState {
MyCoinView(viewModel: myCoinViewModel)
.environmentObject(myCoinState)
appCoordinator.myCoinState.map {
MyCoinView(viewModel: Container.myCoinViewModel())
.environmentObject($0)
.labelsHidden()
}
}
.labelsHidden()
}
}
.onReceive(appCoordinator.$myCoinState) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,28 @@
import Factory
import Home
import MyCoin
import NetworkExtension
import UseCaseProtocol
import NetworkCore
import NetworkExtension
import Pilot
import Repositories
import RepositoryProtocol
import UseCaseProtocol
import UseCases

@MainActor
extension Container {

// Network
static let coinAPI = Factory<CoinAPIProtocol> { Pilot<CoinRoute>() }
static let coinAPI = Factory<CoinAPIProtocol>(scope: .cached) { Pilot<CoinRoute>() }

// ViewModels
static let homeViewModel = Factory {
static let homeViewModel = Factory(scope: .cached) {
HomeViewModel(
myCoinsUseCase: myCoinsUseCase.callAsFunction(),
trendingCoinsUseCase: trendingCoinsUseCase.callAsFunction()
)
}

static let myCoinViewModel = Factory {
MyCoinViewModel(
coinDetailUseCase: coinDetailUseCase.callAsFunction(),
Expand All @@ -37,21 +38,24 @@ extension Container {
}

// Repositories
static let coinRepository = Factory<CoinRepositoryProtocol> {
static let coinRepository = Factory<CoinRepositoryProtocol>(scope: .cached) {
CoinRepository(coinAPI: coinAPI.callAsFunction())
}

// UseCases
static let myCoinsUseCase = Factory<MyCoinsUseCaseProtocol> {
static let myCoinsUseCase = Factory<MyCoinsUseCaseProtocol>(scope: .cached) {
MyCoinsUseCase(repository: coinRepository.callAsFunction())
}
static let trendingCoinsUseCase = Factory<TrendingCoinsUseCaseProtocol> {

static let trendingCoinsUseCase = Factory<TrendingCoinsUseCaseProtocol>(scope: .cached) {
TrendingCoinsUseCase(repository: coinRepository.callAsFunction())
}
static let coinDetailUseCase = Factory<CoinDetailUseCaseProtocol> {

static let coinDetailUseCase = Factory<CoinDetailUseCaseProtocol>(scope: .cached) {
CoinDetailUseCase(repository: coinRepository.callAsFunction())
}
static let getChartPricesUseCase = Factory<GetChartPricesUseCaseProtocol> {

static let getChartPricesUseCase = Factory<GetChartPricesUseCaseProtocol>(scope: .cached) {
GetChartPricesUseCase(repository: coinRepository.callAsFunction())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,20 @@ public struct HomeView: View {
.frame(height: 1.0)
.background(Colors.bgMain.swiftUIColor)
})
.spinner(isPresented: $showingSpinner)
.task {
await viewModel.fetchAllData()
}
.refreshable {
await viewModel.fetchAllData()
await viewModel.fetchAllData(isRefreshing: true)
}
.onReceive(viewModel.$isFetchingData) {
showingSpinner = $0
}
}

@ObservedObject private var viewModel: HomeViewModel
@State private var showingSpinner = false

public init(viewModel: HomeViewModel) {
self.viewModel = viewModel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import UseCaseProtocol

@Published public private(set) var myCoins: [MyCoinItem] = []
@Published public private(set) var trendingCoins: [TrendingCoinItem] = []
@Published public private(set) var isFetchingData = false

public init(
myCoinsUseCase: MyCoinsUseCaseProtocol,
Expand Down Expand Up @@ -48,6 +49,7 @@ import UseCaseProtocol
"tron",
"dogecoin"
]

do {
trendingCoins = try await trendingCoinsUseCase.execute(coinIDs: trendingCoinIDs)
.map(TrendingCoinItem.init)
Expand All @@ -56,11 +58,17 @@ import UseCaseProtocol
}
}

public func fetchAllData() async {
public func fetchAllData(isRefreshing: Bool = false) async {
if !isRefreshing {
isFetchingData = true
}

// Make `fetchMyCoins` and `fetchTrendingCoins` run in parallel
await withTaskGroup(of: Void.self) { taskGroup in
taskGroup.addTask { await self.fetchMyCoins() }
taskGroup.addTask { await self.fetchTrendingCoins() }
}

isFetchingData = false
}
}
22 changes: 22 additions & 0 deletions CryptoPrices/Sources/Home/Tests/HomeTests/HomeViewModelSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ final class HomeViewModelSpec: QuickSpec {
}
.to(beEmpty())
}

it("has the correct value for isFetchingData") {
await expect {
await homeViewModel.isFetchingData
}
.to(beFalse())
}
}

describe("its fetchMyCoins() call") {
Expand Down Expand Up @@ -143,6 +150,11 @@ final class HomeViewModelSpec: QuickSpec {
await expect { await homeViewModel.trendingCoins }
.to(equal(expectedTrendinglCoins))
}

it("gets the correct value for isFetchingData") {
await expect { await homeViewModel.isFetchingData }
.to(beFalse())
}
}

context("when myCoinsUseCase returns success, trendingCoinsUseCase returns failure") {
Expand All @@ -165,6 +177,11 @@ final class HomeViewModelSpec: QuickSpec {
await expect { await homeViewModel.trendingCoins }
.to(beEmpty())
}

it("gets the correct value for isFetchingData") {
await expect { await homeViewModel.isFetchingData }
.to(beFalse())
}
}

context("when myCoinsUseCase and trendingCoinsUseCase return failure") {
Expand All @@ -185,6 +202,11 @@ final class HomeViewModelSpec: QuickSpec {
await expect { await homeViewModel.trendingCoins }
.to(beEmpty())
}

it("gets the correct value for isFetchingData") {
await expect { await homeViewModel.isFetchingData }
.to(beFalse())
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ struct CurrentPriceSection: View {
})
.padding(EdgeInsets(top: 8.0, leading: 10.0, bottom: 8.0, trailing: 10.0))
.foregroundColor(Colors.guppieGreen.swiftUIColor)
.background(Colors.scandal.swiftUIColor)
.background(
coinItem.priceChangePercentage24H > 0.0
? Colors.scandal.swiftUIColor
: Colors.carnation.swiftUIColor.opacity(0.3)
)
.cornerRadius(20.0)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public struct MyCoinView: View {
.safeAreaInset(edge: .bottom, content: {
footerView
})
.spinner(isPresented: $showingSpinner)
.task {
await viewModel.fetchData(id: myCoinState.id, timeFrameItem: selectedTimeFrameItem)
}
Expand All @@ -56,13 +57,21 @@ public struct MyCoinView: View {
selectedTimeFrameItem = tempSelectedTimeFrameItem
}
}
.onReceive(viewModel.$isFetchingData) {
showingSpinner = $0
}
.refreshable {
selectedTimeFrameItem = .init(timeFrame: .oneDay)
await viewModel.fetchCoinDetail(id: myCoinState.id)
await viewModel.fetchData(
id: myCoinState.id,
timeFrameItem: selectedTimeFrameItem,
isRefreshing: true
)
}
}

@ObservedObject private var viewModel: MyCoinViewModel
@State private var showingSpinner = false

public init(viewModel: MyCoinViewModel) {
self.viewModel = viewModel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import UseCaseProtocol
@Published public private(set) var coinDetail: CoinDetailItem?
@Published public private(set) var chartData: [ChartDataPointUIModel] = []
@Published public private(set) var isSuccess = false
@Published public private(set) var isFetchingData = false

public init(
coinDetailUseCase: CoinDetailUseCaseProtocol,
Expand Down Expand Up @@ -45,10 +46,16 @@ import UseCaseProtocol
}
}

public func fetchData(id: String, timeFrameItem: TimeFrameItem) async {
public func fetchData(id: String, timeFrameItem: TimeFrameItem, isRefreshing: Bool = false) async {
if !isRefreshing {
isFetchingData = true
}

await withTaskGroup(of: Void.self) { taskGroup in
taskGroup.addTask { await self.fetchCoinDetail(id: id) }
taskGroup.addTask { await self.fetchChartPricesData(id: id, timeFrameItem: timeFrameItem) }
}

isFetchingData = false
}
}
Loading

0 comments on commit 7e3ecc4

Please sign in to comment.