This is an sample Crypto market prices ap built with SwiftUI and modularization architecture. The application data is making use of the free APIs provided by Coingecko.
MIT License
33
stars
8
forks
source link
[#103] [UI+Integrate] Display a loading spinner while fetching the data #106
Create the CircularProgressView, which shows a (static) ring view with a given progress value.
Create the spinner view modifier, which can be attached to a view to show a CircularProgressView instance with a rotation animation. Apply the modifier to HomeView and MyCoinView.
Update the method calls in HomeViewModel and MyCoinViewModel with a isRefreshing parameter to distinguish the context (view appearing or data refreshing)
Update the lifetime of Factory's creation dependencies:
It started with a bug. When users tap a coin item on the Home to navigate to the Detail, the view displays the data from the previous state while waiting for the network response. At first, I thought there could be something wrong with the @EnvironmentObject. Actually, the root cause is that we pass the same instance of MyCoinViewModel when we create the new MyCoinView:
struct AppView: View {
@Injected(Container.myCoinViewModel) private var myCoinViewModel
var body: some View {
// ...
MyCoinView(viewModel: myCoinViewModel)
// ...
}
}
hence the update is passing the instance from the Container instead of keeping around an injected one:
From this, I reconsidered the lifetime of the dependencies:
For the service types like the network, the Repositorys, and the UseCases, it's fine to keep only one instance of them across the app since they contain just some kind of work on demand (fetching and returning data). They don't keep any internal state, so there is no worry about conflict or race conditions. The Factory provides some predefined scope (we can define a custom one) like cached, singleton, or shared ... For our simple app, there's seem no difference between these so I went with cached.
For the presentation layer types like view models, in general, their lifetime should be the same as their corresponding views, except for the HomeView since it is the root view of the app (it's always there). So the HomeViewModel can be cached.
Insight 📝
While creating the loading spinner, at first, I styled it with the same purple color as the Android did (the color choice seems to be related to the MaterialDesign thing)
IMHO, the purple color looks out of place with others from the existing palette, especially in light mode. It should be a complement or a contrast one, the purple is not one of these (I'm no expert in UI/UX design 🙏) Here the app shows the spinner with the purple color in case you wonder:
Dark mode
Light mode
So I tried to pick one from the existing colors and found that tiffanyBlue looks good in light and dark modes.
But it's just a matter of preferences. Please raise your thoughts, and I'm happy to make another choice 🙏
What happened 👀
CircularProgressView
, which shows a (static) ring view with a given progress value.spinner
view modifier, which can be attached to a view to show aCircularProgressView
instance with a rotation animation. Apply the modifier toHomeView
andMyCoinView
.HomeViewModel
andMyCoinViewModel
with aisRefreshing
parameter to distinguish the context (view appearing or data refreshing)Update the lifetime of
Factory
's creation dependencies:It started with a bug. When users tap a coin item on the Home to navigate to the Detail, the view displays the data from the previous state while waiting for the network response. At first, I thought there could be something wrong with the
@EnvironmentObject.
Actually, the root cause is that we pass the same instance ofMyCoinViewModel
when we create the newMyCoinView
:hence the update is passing the instance from the
Container
instead of keeping around an injected one:For the service types like the network, the
Repository
s, and theUseCase
s, it's fine to keep only one instance of them across the app since they contain just some kind of work on demand (fetching and returning data). They don't keep any internal state, so there is no worry about conflict or race conditions. TheFactory
provides some predefined scope (we can define a custom one) likecached
,singleton
, orshared
... For our simple app, there's seem no difference between these so I went withcached
.For the presentation layer types like view models, in general, their lifetime should be the same as their corresponding views, except for the
HomeView
since it is the root view of the app (it's always there). So theHomeViewModel
can be cached.Insight 📝
While creating the loading spinner, at first, I styled it with the same purple color as the Android did (the color choice seems to be related to the MaterialDesign thing)
So I tried to pick one from the existing colors and found that
tiffanyBlue
looks good in light and dark modes.But it's just a matter of preferences. Please raise your thoughts, and I'm happy to make another choice 🙏
Proof Of Work 📹