Skip to content
This repository has been archived by the owner on Dec 4, 2022. It is now read-only.

Commit

Permalink
Added country details screen #5 (#24)
Browse files Browse the repository at this point in the history
* feature: added statistic parser and statistic API

* configured koin
* added repository for statistic
* added jsoup to gradle dependencies
* added models for statistic from API and from html parser
* renamed total models and repository, interactor
* added statistic api

[SO-5]

* fix: fixed merge conflicts

* fixed merge conflicts

[SO-5]

* feature: added database implementation for statistics

* refactored module DI
* implemented logic for saving data

[SO-5]

* feature: added database implementation for statistics

* added ID

[SO-5]

* feature: added database implementation for statistics

* created two primary keys

[SO-5]

* feature: added database implementation for statistics

* changed primary key to province

[SO-5]

* feature: added database implementation for statistics

* added inject StatisticCovidCache to Module.kt

[SO-5]

* Fixes

* feature: created implementation getting logic from database to viewmodel

* renamed Country.kt to TotalCountry.kt
* created model StatisticCountry.kt
* added mapping for StatisticCountry.kt

[SO-5]

* feature: created statistic for country

* created viewmodel
* created fragment
* create views for fragment, recycler item
* create DiffUtil callback

[SO-5]

* feature: added throwable for parser

* created throwable for parser
* implemented logic for mapping
* added error to strings.xml
* added icon for StatisticCountryFragment.kt

[SO-5]

* fix: fixed data binding and parser

* fixed data format value in mapper for xml
* fixed parser, changed urls and remove const count countries
* remove deprecated databinding execute method and added recommended by IDE

[CO-5]

* feature: added country details country statistic

* added click listener to CountriesListAdapter.kt
* added inject logic to DI
* added safe args to gradle
* added show country statistic method to NavigationExtensions.kt

[CO-5]

* feature: fetch confirmed-deaths-recovered in one model

* added to DayStatistic three confirmed-deaths-recovered

[SO-5]

* fix: fixed statistic data calculating

* fixed fetching statistic data
* fixed calculating statistic by day

[CO-5]

* feature: added collapsed view for statistic screen

* added draggable icon
* configured fragment_statistic_country.xml
* changed colorPrimaryLight
* added BottomSheetBehaviour init method to StatisticCountryFragment.kt

[SO-5]

* feature: added chart

* added MPAChart lib
* added RxRelay lib
* added temp chart to fragment
* added time format method to DateExtensions.kt
* added behavior relay to StatisticCountryViewModel.kt

[SO-5]

* feature: added ChartView

* incremented chart lib
* created custom view chart
* added map-method for float to FormatExtensions.kt

[SO-5]

* Fixed statistics list and refactoring

* Merge the latest Taras's changes

* feature: changed time impl

* changed time format from string to long in data layers
* created view for total data
* removed unusable methods form cache layer

[SO-5]

* feature: added total to statistic

* added total
* added total string
* created total view model
* renamed chart view model
* fixed url for parser

[SO-5]

* UI minor changes

* Show a date in total values under the chart

* Increment a database version

* Changed FAB behaviour

Co-authored-by: KoiDev <tarasfreedev@gmail.com>
  • Loading branch information
dmitriy-chernysh and DigitalKoi authored Apr 3, 2020
1 parent 62b26fa commit cab4440
Show file tree
Hide file tree
Showing 91 changed files with 2,333 additions and 324 deletions.
12 changes: 5 additions & 7 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.google.firebase.crashlytics'
apply plugin: "androidx.navigation.safeargs.kotlin"

android {
compileSdkVersion rootProject.compileSdkVersion
Expand Down Expand Up @@ -108,7 +109,7 @@ android {
}
}

dataBinding.enabled = true
android.dataBinding.enabled = true

kapt.correctErrorTypes = true
}
Expand Down Expand Up @@ -151,20 +152,17 @@ dependencies {
//Rx
implementation deps.rxAndroid
implementation deps.rxKotlin
implementation deps.rxRelay

//Glide
implementation deps.glide
kapt deps.glideCompiler

//Logs
implementation deps.timber
// debugImplementation deps.stetho
// debugImplementation deps.flipper
// debugImplementation deps.stethoNetworkHelper
// debugImplementation deps.soloader

// releaseImplementation deps.flipperNoop
//
//Chart
implementation deps.mpaChart

//Beta testing
implementation deps.testfairy
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
tools:replace="android:allowBackup">
<activity
android:name="com.mobiledevpro.app.ui.common.SplashActivity"
android:theme="@style/AppTheme.Splash">
android:theme="@style/AppTheme.Splash"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
Expand Down
13 changes: 5 additions & 8 deletions app/src/main/java/com/mobiledevpro/app/common/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import android.util.Log
import com.google.android.gms.tasks.OnCompleteListener
import com.google.firebase.iid.FirebaseInstanceId
import com.mobiledevpro.app.BuildConfig
import com.mobiledevpro.app.di.*
import com.mobiledevpro.app.di.dataLocalModule
import com.mobiledevpro.app.di.dataModule
import com.mobiledevpro.app.di.dataRemoteModule
import com.mobiledevpro.app.di.domainModule
import com.mobiledevpro.app.di.uiModule
import com.mobiledevpro.data.LOG_TAG_DEBUG
import com.testfairy.TestFairy
import org.koin.android.ext.koin.androidContext
Expand Down Expand Up @@ -98,11 +102,4 @@ class App : Application() {
// Timber.plant(CrashlyticsTree())
}
}

/*
companion object {
val flipperNetworkPlugin = if (BuildConfig.DEBUG) Т() else null
}
*/
}
95 changes: 81 additions & 14 deletions app/src/main/java/com/mobiledevpro/app/di/Module.kt
Original file line number Diff line number Diff line change
@@ -1,25 +1,38 @@
package com.mobiledevpro.app.di

import com.mobiledevpro.app.ui.main.viemodel.MainViewModel
import com.mobiledevpro.app.ui.statistic.viewmodel.StatisticCountryViewModel
import com.mobiledevpro.app.ui.total.viewmodel.TotalViewModel
import com.mobiledevpro.app.utils.provider.DefaultResourceProvider
import com.mobiledevpro.app.utils.provider.ResourceProvider
import com.mobiledevpro.data.repository.userdata.CovidCache
import com.mobiledevpro.data.repository.userdata.CovidRemote
import com.mobiledevpro.data.repository.parcer.StatisticsParserHtml
import com.mobiledevpro.data.repository.statistic.DefaultStatisticDataRepository
import com.mobiledevpro.data.repository.statistic.StatisticCovidCache
import com.mobiledevpro.data.repository.statistic.StatisticCovidRemote
import com.mobiledevpro.data.repository.userdata.DefaultTotalDataRepository
import com.mobiledevpro.data.repository.userdata.TotalCovidCache
import com.mobiledevpro.data.repository.userdata.TotalCovidRemote
import com.mobiledevpro.domain.statistic.data.DefaultStatisticDataInteractor
import com.mobiledevpro.domain.statistic.data.StatisticDataInteractor
import com.mobiledevpro.domain.statistic.data.StatisticDataRepository
import com.mobiledevpro.domain.totaldata.DefaultTotalDataInteractor
import com.mobiledevpro.domain.totaldata.TotalDataInteractor
import com.mobiledevpro.domain.totaldata.TotalDataRepository
import com.mobiledevpro.local.database.DefaultCovidCache
import com.mobiledevpro.local.database.AppDatabase
import com.mobiledevpro.local.database.statistic.DefaultStatisticsCovidCache
import com.mobiledevpro.local.database.total.DefaultTotalCovidCache
import com.mobiledevpro.local.storage.PreferencesHelper
import com.mobiledevpro.local.storage.PreferencesHelperImpl
import com.mobiledevpro.remote.implementation.DefaultTotalDataIRemote
import com.mobiledevpro.remote.implementation.DefaultStatisticCovidRemote
import com.mobiledevpro.remote.implementation.DefaultStatisticsParserHtml
import com.mobiledevpro.remote.implementation.DefaultTotalCovidRemote
import com.mobiledevpro.remote.service.RemoteServiceFactory
import com.mobiledevpro.remote.service.http.OkHttpFactory
import com.mobiledevpro.remote.service.interceptor.ApiRequestInterceptor
import com.mobiledevpro.remote.service.interceptor.ApiResponseInterceptor
import com.mobiledevpro.remote.service.interceptor.ApiStatisticsRequestInterceptor
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.core.qualifier.named
import org.koin.dsl.module

/**
Expand All @@ -32,36 +45,90 @@ import org.koin.dsl.module
*/

val uiModule = module {
viewModel { TotalViewModel(get(), get()) }

viewModel { MainViewModel() }

viewModel {
TotalViewModel(
resourceProvider = get(),
totalInteractor = get(),
statisticInteractor = get()
)
}

viewModel {
StatisticCountryViewModel(
resourceProvider = get(),
statisticInteractor = get()
)
}

single { DefaultResourceProvider(androidContext().resources) as ResourceProvider }
}

val domainModule = module {
single { DefaultTotalDataInteractor(get()) as TotalDataInteractor }
single { DefaultTotalDataInteractor(totalDataRepository = get()) as TotalDataInteractor }
single { DefaultStatisticDataInteractor(statisticDataRepository = get()) as StatisticDataInteractor }
}

val dataModule = module {
single { DefaultTotalDataRepository(get(), get()) as TotalDataRepository }
single {
DefaultTotalDataRepository(
totalCovidCache = get(),
totalCovidRemote = get()
) as TotalDataRepository
}
single { DefaultStatisticDataRepository(
statisticsCache = get(),
statisticRemote = get(),
statisticsParserHtml = get()
) as StatisticDataRepository }
}

val dataLocalModule = module {
single { DefaultTotalDataIRemote(get()) as CovidRemote }
single { DefaultCovidCache(get()) as CovidCache }
single { PreferencesHelperImpl(get()) as PreferencesHelper }
single { DefaultTotalCovidRemote(apiTotal = get()) as TotalCovidRemote }
single { DefaultTotalCovidCache(database = get()) as TotalCovidCache }

single { DefaultStatisticCovidRemote(apiStatistic = get()) as StatisticCovidRemote }
single { DefaultStatisticsCovidCache(database = get()) as StatisticCovidCache }

single { AppDatabase.getInstance(androidContext()) }

single { PreferencesHelperImpl(appContext = get()) as PreferencesHelper }

}

val dataRemoteModule = module {
// retrofit instance, firebase database, etc
single { RemoteServiceFactory(get()).buildStackOverFlowApi() }
// retrofit instance, firebase database, html parser etc
single {
RemoteServiceFactory(
client = get(named(TOTAL_OK_HTTP_CLIENT))
).buildCovidTotalApi()
}
single {
RemoteServiceFactory(
client = get(named(STATISTIC_OK_HTTP_CLIENT))
).buildCovidFullStatisticsApi()
}

single(named(STATISTIC_OK_HTTP_CLIENT)) {
OkHttpFactory().buildOkHttpClient(
listOf(
ApiResponseInterceptor(),
ApiRequestInterceptor()
ApiStatisticsRequestInterceptor()
)
)
}

single(named(TOTAL_OK_HTTP_CLIENT)) {
OkHttpFactory().buildOkHttpClient(
listOf(ApiResponseInterceptor())
)
}

single { DefaultStatisticsParserHtml() as StatisticsParserHtml }
}


private const val TOTAL_OK_HTTP_CLIENT = "total"
private const val STATISTIC_OK_HTTP_CLIENT = "statistics"
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.mobiledevpro.app.ui.countries.adapter.CountriesListAdapter
import com.mobiledevpro.app.ui.main.viemodel.MainViewModel
import com.mobiledevpro.app.ui.total.viewmodel.TotalViewModel
import com.mobiledevpro.app.utils.Navigation
import com.mobiledevpro.app.utils.showStatisticCountry
import com.mobiledevpro.commons.fragment.BaseFragment
import kotlinx.android.synthetic.main.fragment_countries_list.*
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
Expand Down Expand Up @@ -79,7 +80,7 @@ class CountriesListFragment : BaseFragment() {

rv_countries_list?.layoutManager = layoutManager
rv_countries_list?.setHasFixedSize(true)
rv_countries_list?.adapter = CountriesListAdapter()
rv_countries_list?.adapter = CountriesListAdapter(this::showStatisticCountry)
rv_countries_list.addItemDecoration(divider)
}

Expand All @@ -92,6 +93,7 @@ class CountriesListFragment : BaseFragment() {
if (this.isNotEmpty()) {
onActionViewExpanded()
setQuery(this, true)
mainViewModel.setFabActionCloseCountrySearch()
}
}

Expand All @@ -103,19 +105,42 @@ class CountriesListFragment : BaseFragment() {
return true
}
})

setOnSearchClickListener {
mainViewModel.setFabActionCloseCountrySearch()
}
}
}

private fun observeEvents() {
mainViewModel.eventNavigateTo.observe(viewLifecycleOwner, Observer {
it.peekContent().let { navigateTo ->
if (navigateTo == Navigation.NAVIGATE_TO_SEARCH_COUNTRY) {
searchView.apply {
onActionViewExpanded()
totalViewModel.getQuery().apply {
setQuery(this, true)
when (navigateTo) {
Navigation.NAVIGATE_TO_SEARCH_COUNTRY -> {
searchView.apply {
onActionViewExpanded()
totalViewModel.getQuery().apply {
setQuery(this, true)
}
}

mainViewModel.setFabActionCloseCountrySearch()
}

Navigation.NAVIGATE_CLOSE_SEARCH_COUNTRY -> {
searchView.apply {
onActionViewCollapsed()
totalViewModel.getQuery().apply {
setQuery(this, true)
}
}

mainViewModel.setFabActionShowCountrySearch()
}

else -> {
}

}
}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.mobiledevpro.app.R
import com.mobiledevpro.app.databinding.ItemCountryBinding
import com.mobiledevpro.app.utils.diff.CountiesDiffUtil
import com.mobiledevpro.domain.model.Country
import com.mobiledevpro.domain.model.TotalCountry

/**
* Adapter for RecyclerView Countries list
Expand All @@ -20,22 +20,24 @@ import com.mobiledevpro.domain.model.Country
* http://androiddev.pro
*
*/
class CountriesListAdapter : RecyclerView.Adapter<CountriesListAdapter.ViewHolder>() {
class CountriesListAdapter(
private val onClick: (countryName: String) -> Unit
) : RecyclerView.Adapter<CountriesListAdapter.ViewHolder>() {

private var countriesList: ArrayList<Country> = ArrayList()
private var countriesList: ArrayList<TotalCountry> = ArrayList()

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CountryItemViewHolder =
CountryItemViewHolder(parent)


override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if (holder is CountryItemViewHolder)
holder.bind(countriesList[holder.adapterPosition])
holder.bind(countriesList[holder.adapterPosition], onClick)
}

override fun getItemCount() = countriesList.size

fun populateList(update: ArrayList<Country>) {
fun populateList(update: ArrayList<TotalCountry>) {
val callback = CountiesDiffUtil(countriesList, update)
val result = DiffUtil.calculateDiff(callback)
countriesList.clear()
Expand All @@ -47,9 +49,9 @@ class CountriesListAdapter : RecyclerView.Adapter<CountriesListAdapter.ViewHolde
companion object {
@JvmStatic
@BindingAdapter("items")
fun RecyclerView.bindItems(items: List<Country>) {
fun RecyclerView.bindItems(items: List<TotalCountry>?) {
val adapter = adapter as CountriesListAdapter
adapter.populateList(ArrayList(items))
adapter.populateList(if (items == null) ArrayList() else ArrayList(items))
}
}

Expand All @@ -66,9 +68,14 @@ class CountriesListAdapter : RecyclerView.Adapter<CountriesListAdapter.ViewHolde

) : ViewHolder(binding.root) {

fun bind(item: Country) {
fun bind(
item: TotalCountry,
onClick: (countryName: String) -> Unit
) {
binding.item = item
binding.executePendingBindings()

itemView.setOnClickListener { onClick(item.country) }
}
}
}
Loading

0 comments on commit cab4440

Please sign in to comment.