Aplikasi Covid-19 using MVP

Fikri Dzakwan
10 min readAug 9, 2020

Pada kali ini saya akan membuat Aplikasi Covid-19, di aplikasi ini kita dapat melihat seberapa banyak orang yg telah terkena virus ini, dan kita juga bisa tahu grafik setiap negara yg telah terkena virus covid-19. Lagsung saja kita mulai.

Syarat:

  • Menggunakan Android Studio
  • Menggunakan bahasa Kotlin
  • Menyiapkan Emulator atau Smartphone degan versi android diatas 16 atau Jelly bean

Persiapan

Pilih Empty Activity dan tekan next

Buat nama project Covid-19 MVP atau sesuka anda, lalu tekan finish

Buka build.gradle(Module: app)

//  depedency
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"

implementation 'com.google.android.material:material:1.1.0'

implementation 'de.hdodenhof:circleimageview:3.1.0'

implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"

implementation 'com.github.bumptech.glide:glide:4.8.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'

implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3'

implementation 'com.amitshekhar.android:android-networking:1.0.2'

Lalu tambahakan kode berikut, kode ini berfungsi dibutuhkan untuk project kali ini

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

Masih didalam module build.gradel(Module: app) tambahkan compileOptions, dan letakan diatas buildType

maven { url ‘https://jitpack.io' }

Dan tambahkan kode berikut didalam build.gradel(Project: {Nama_Aplikasi}), dan letakan di allproject

Setelah itu tekan tombol sync dipojok kanan atas, dan tunggu sebentar karen Android Studio akan mendownload file yg dibutuhkan. Apabila anda sudah pernah menggunakan depedncy tersebut sinkronisasi tidak akan berjalan lama

Buat lah package seperti berikut

Setelah itu buat lah activity ChartCountryActivity. Kemudian buka lah activity_main.xml

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.main.MainActivity">

<LinearLayout
android:id="@+id/lay_linear1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginStart="@dimen/dp8"
android:layout_marginEnd="@dimen/dp8">

<androidx.appcompat.widget.SearchView
android:id="@+id/search_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp8"
android:layout_marginBottom="@dimen/dp8"
android:layout_weight="1"
android:background="@drawable/box_search_country"
app:queryHint="Cari Negara"
android:textCursorDrawable="@null"
app:iconifiedByDefault="false"
app:queryBackground="@null"
app:actionViewClass="android.widget.SearchView"/>

<Button
android:id="@+id/btn_sequence"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/dp2"
android:layout_marginStart="@dimen/dp2"
android:layout_marginTop="@dimen/dp8"
android:layout_marginBottom="@dimen/dp8"
android:background="@drawable/ic_sequence"
android:layout_weight="5"/>

</LinearLayout>

<LinearLayout
android:id="@+id/lay_globe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/lay_linear1"
android:layout_marginStart="@dimen/dp8"
android:layout_marginEnd="@dimen/dp8"
android:background="@drawable/bg_blue"
android:orientation="horizontal"
android:baselineAligned="false">

<!-- Region text confirmed-->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp8"
android:layout_marginEnd="@dimen/dp8"
android:layout_weight="1"
android:orientation="vertical">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:textSize="16sp"
android:layout_marginTop="@dimen/dp8"
android:text="@string/confirmed"/>

<TextView
android:id="@+id/tv_confirmed_globe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginBottom="@dimen/dp8"
android:text="-"/>

</LinearLayout>
<!-- Endregion-->

<!-- Region text recovered-->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp8"
android:layout_marginEnd="@dimen/dp8"
android:layout_weight="1"
android:orientation="vertical">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:textSize="16sp"
android:layout_marginTop="@dimen/dp8"
android:text="@string/recovered"/>

<TextView
android:id="@+id/tv_recovered_globe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginBottom="@dimen/dp8"
android:text="-"/>

</LinearLayout>
<!-- Endregion-->

<!-- Region text deaths-->
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:layout_weight="1"
android:orientation="vertical">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:textSize="16sp"
android:layout_marginTop="10dp"
android:text="@string/deaths"/>

<TextView
android:id="@+id/tv_deaths_globe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginBottom="@dimen/dp8"
android:text="-"/>


</LinearLayout>
<!-- Endregion-->

</LinearLayout>

<LinearLayout
android:id="@+id/lay_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/lay_globe"
android:layout_marginStart="@dimen/dp16"
android:layout_marginEnd="@dimen/dp16"
android:orientation="horizontal">

<TextView
style="@style/TextContentMainActivity"
android:layout_marginTop="@dimen/dp8"
android:layout_weight="4"
android:text="@string/countries"/>

<TextView
style="@style/TextContentMainActivity"
android:layout_marginTop="@dimen/dp8"
android:layout_weight="5"
android:text="@string/total_cases"/>

<TextView
style="@style/TextContentMainActivity"
android:layout_marginTop="@dimen/dp8"
android:layout_weight="5"
android:text="@string/recovered"/>

<TextView
style="@style/TextContentMainActivity"
android:layout_marginTop="@dimen/dp8"
android:layout_weight="5"
android:text="@string/deaths"/>

</LinearLayout>

<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminate="true"/>

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/lay_header"
android:layout_marginTop="@dimen/dp8"
android:layout_marginBottom="@dimen/dp8">

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_country"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="@layout/list_country"/>

</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

</RelativeLayout>

Dan tambahkan kode berikut, setelah itu buka lah activity_chart_country.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/dp16"
android:layout_weight="1"
android:background="@drawable/bg_header_gray"
android:orientation="vertical"
android:padding="10dp">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal"
tools:ignore="NestedWeight">

<ImageView
android:id="@+id/img_flag_chart"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/dp8"
android:layout_weight="1"
android:src="@drawable/ic_launcher_background"
tools:ignore="NestedWeight" />

<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/dp8"
android:layout_weight="1"
app:cardCornerRadius="@dimen/dp8"
app:cardElevation="@dimen/dp4">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">

<TextView
android:id="@+id/tv_country_chart"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/countries"
android:textColor="@color/colorPrimaryDark"
android:textSize="20sp"
android:textStyle="bold" />

<TextView
android:id="@+id/tv_curent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/currently"
android:textAlignment="center"
android:textSize="12sp"
android:textStyle="bold" />

</LinearLayout>

</androidx.cardview.widget.CardView>

</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal"
tools:ignore="NestedWeight">

<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/dp8"
android:layout_weight="1"
app:cardCornerRadius="@dimen/dp8"
app:cardElevation="@dimen/dp4">

<LinearLayout
style="@style/LinearLayoutForCardView"
android:background="@color/orange">

<TextView
style="@style/TitleInsideCardViewInChart"
android:text="@string/total_confirmed"
android:textColor="@android:color/white" />

<TextView
android:id="@+id/tv_total_confirmed_current"
style="@style/ContentTextInsideCardViewChart"
android:text="@string/currently"
android:textColor="@android:color/white" />

</LinearLayout>

</androidx.cardview.widget.CardView>

<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/dp8"
android:layout_weight="1"
app:cardCornerRadius="@dimen/dp8"
app:cardElevation="@dimen/dp4">

<LinearLayout
style="@style/LinearLayoutForCardView"
android:background="@color/orange_grey">

<TextView
style="@style/TitleInsideCardViewInChart"
android:text="@string/new_confirmed"
android:textColor="@android:color/white" />

<TextView
android:id="@+id/tv_new_confirmed_current"
style="@style/ContentTextInsideCardViewChart"
android:text="@string/currently"
android:textColor="@android:color/white" />

</LinearLayout>

</androidx.cardview.widget.CardView>

</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal"
tools:ignore="NestedWeight">

<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/dp8"
android:layout_weight="1"
app:cardCornerRadius="@dimen/dp8"
app:cardElevation="@dimen/dp4">

<LinearLayout
style="@style/LinearLayoutForCardView"
android:background="@color/yellow">

<TextView
style="@style/TitleInsideCardViewInChart"
android:text="@string/total_deaths"
android:textColor="@android:color/holo_red_light" />

<TextView
android:id="@+id/tv_total_deaths_current"
style="@style/ContentTextInsideCardViewChart"
android:text="@string/currently"
android:textColor="@android:color/holo_red_light" />

</LinearLayout>

</androidx.cardview.widget.CardView>

<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/dp8"
android:layout_weight="1"
app:cardCornerRadius="@dimen/dp8"
app:cardElevation="@dimen/dp4">

<LinearLayout
style="@style/LinearLayoutForCardView"
android:background="@color/yellow_grey">

<TextView
style="@style/TitleInsideCardViewInChart"
android:text="@string/new_deaths"
android:textColor="@android:color/holo_red_light" />

<TextView
android:id="@+id/tv_new_deaths_current"
style="@style/ContentTextInsideCardViewChart"
android:text="@string/currently"
android:textColor="@android:color/holo_red_light" />

</LinearLayout>

</androidx.cardview.widget.CardView>

</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal"
tools:ignore="NestedWeight">

<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/dp8"
android:layout_weight="1"
app:cardCornerRadius="@dimen/dp8"
app:cardElevation="@dimen/dp4">

<LinearLayout
style="@style/LinearLayoutForCardView"
android:background="@color/colorAccent">

<TextView
style="@style/TitleInsideCardViewInChart"
android:text="@string/total_recoverd"
android:textColor="@android:color/black" />

<TextView
android:id="@+id/tv_total_recovered_current"
style="@style/ContentTextInsideCardViewChart"
android:text="@string/currently"
android:textColor="@android:color/holo_red_light" />

</LinearLayout>

</androidx.cardview.widget.CardView>

<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/dp8"
android:layout_weight="1"
app:cardCornerRadius="@dimen/dp8"
app:cardElevation="@dimen/dp4">

<LinearLayout
style="@style/LinearLayoutForCardView"
android:background="@color/blue_grey">

<TextView
style="@style/TitleInsideCardViewInChart"
android:text="@string/new_recovered"
android:textColor="@android:color/black"/>

<TextView
android:id="@+id/tv_new_recovered_current"
style="@style/ContentTextInsideCardViewChart"
android:text="@string/currently"
android:textColor="@android:color/holo_red_light" />

</LinearLayout>

</androidx.cardview.widget.CardView>

</LinearLayout>

</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/dp4"
android:orientation="horizontal"
android:layout_weight="1">

<com.github.mikephil.charting.charts.BarChart
android:id="@+id/chart_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

</LinearLayout>

</LinearLayout>

Tambah kan kode berikut pada activity_chart_country.xml. Lalu buat lah layout baru dan beri nama list_country.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@android:color/white"
android:orientation="vertical">

<LinearLayout
android:id="@+id/lay_globe_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/dp8"
android:layout_margin="@dimen/dp8"
android:background="@drawable/bg_header_gray"
android:orientation="horizontal">

<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/img_flag_country"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginStart="@dimen/dp4"
android:src="@mipmap/ic_launcher_round"/>

<TextView
android:id="@+id/tv_country_name"
style="@style/TextContentListCountry"
android:layout_weight="4"
android:textStyle="bold"
android:text="@string/countries"/>

<TextView
android:id="@+id/tv_country_total_case"
style="@style/TextContentListCountry"
android:layout_weight="5"
android:text="@string/total_cases"/>

<TextView
android:id="@+id/tv_country_total_recovered"
style="@style/TextContentListCountry"
android:layout_weight="5"
android:text="@string/recovered"/>

<TextView
android:id="@+id/tv_country_total_deaths"
style="@style/TextContentListCountry"
android:layout_weight="5"
android:text="@string/deaths"/>

</LinearLayout>

</LinearLayout>

Dan tambahkan kode berikut. Tambahkan juga values color, string, dan style

colors.xml

<color name="orange">#FF5722</color>
<color name="yellow">#FFEB3B</color>
<color name="red">#B71C1C</color>

<color name="orange_grey">#FF9E80</color>
<color name="yellow_grey">#FFFF8D</color>
<color name="blue_grey">#84FFFF</color>

strings.xml

<string name="confirmed">Confirmed</string>
<string name="deaths">Deaths</string>
<string name="recovered">Recovered</string>
<string name="countries">Countries</string>
<string name="total_cases">Total cases</string>
<string name="nama_negara">Country Name</string>
<string name="currently">Currently</string>
<string name="total_confirmed">Total Confirmed</string>
<string name="new_confirmed">New Confirmed</string>
<string name="total_deaths">Total Deaths</string>
<string name="total_recoverd">Total Recoverd</string>
<string name="new_deaths">New Deaths</string>
<string name="new_recovered">New Recoverd</string>

styles.xml

<style name="LinearLayoutForCardView">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
<item name="android:gravity">center</item>
<item name="android:orientation">vertical</item>
</style>

<style name="TitleInsideCardViewInChart">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textAlignment">center</item>
<item name="android:textSize">12sp</item>
<item name="android:textStyle">bold</item>
</style>

<style name="ContentTextInsideCardViewChart">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textAlignment">center</item>
<item name="android:textSize">20sp</item>
<item name="android:textStyle">bold</item>
</style>

<style name="TextContentListCountry">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">@android:color/black</item>
<item name="android:layout_gravity">center_horizontal</item>
<item name="android:textSize">12sp</item>
</style>

<style name="TextContentMainActivity">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">@android:color/black</item>
<item name="android:textStyle">bold</item>
<item name="android:textSize">12sp</item>
</style>

Dan buat layout baru dengan nama dimens.xml dan letakan didalam package values. dan tambakan kode yg sudah diberikan

dimens.xml

<dimen name="dp2">2dp</dimen>
<dimen name="dp8">8dp</dimen>
<dimen name="dp6">6dp</dimen>
<dimen name="dp16">16dp</dimen>
<dimen name="dp4">4dp</dimen>

lalu buka package drawable dan buat layout bg_blue.xml, bg_header_gray.xml, dan box_search_country.xml. Dan tambah kan kode yg sudah diberikan

bg_blue.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/colorPrimaryDark"/>
<corners android:radius="@dimen/dp6"/>
</shape>

bg_header.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#E4E4E4"/>

</shape>

box_search_country.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android">

<stroke android:color="@color/colorPrimary"
android:width="@dimen/dp2"/>

<corners android:radius="8dp"/>

</shape>

Tambahkan vector swap vert pada package drawable dan beri nama sequence

Coding

Buat lah object pada package network dan beri nama ApiClient, dan tambahkan kode berikut

fun getClient(): ApiService {
val logging = HttpLoggingInterceptor()
logging.level = HttpLoggingInterceptor.Level.BODY

val httpClient = OkHttpClient.Builder()

httpClient.addInterceptor(logging)

val retrofit = Retrofit.Builder()
.baseUrl("https://api.covid19api.com/")
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build())
.build()

return retrofit.create(ApiService::class.java)
}

Fungsi ApiClient adalah kita mensetting retrofit agar dapat digunakan untuk mendapatkan data dari database. Kemudian buatlah Interface pada package network, beri nama ApiService

@GET("summary")
fun getAllCountry(): Call<AllCountries>

@GET("dayone/country/{country}")
fun getInfoService(@Path("country") dataCovid: String): Call<List<InfoCountry>>

Fungsi ApiService adalah sebagai endpoint. Retrofit membutuhkan POJO guna akses transaksi ke dalam struktur dari JSON, buatlah file Model.kt pada package model, dan tambahkan kode berikut

data class AllCountries (val Global: World, val Countries: ArrayList<Countries>)

data class World (
val TotalConfirmed: String = "",
val TotalDeaths: String = "",
val TotalRecovered: String = ""
)

data class Countries(
val Country: String = "",
val CountryCode: String = "",
val Slug: String = "",
val NewConfirmed: String = "",
val NewDeaths: String = "",
val TotalDeaths: String = "",
val NewRecovered: String = "",
val TotalRecovered: String = "",
val TotalConfirmed: String = "",
val Date: String = ""
)

data class InfoCountry(
val Confirmed: String = "",
val Recovered: String = "",
val Deaths: String = "",
val Active: String = "",
val Date: String = ""
)

Setelah kita mensetting semua data yg dibutuh kan untuk didapat kan mari kita buat class adapter pada package, beri nama CountryAdapter dan tambahkan kode berikut dalam class adapter

class CountryAdapter(val country: ArrayList<Countries>, val clickListener: (Countries) -> Unit):
RecyclerView.Adapter<CountryAdapter.CountryViewHolder>(), Filterable {

var countryFilterList = ArrayList<Countries>()
init {
countryFilterList = country
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CountryViewHolder {
return CountryViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.list_country, parent, false))
}

override fun getItemCount(): Int = countryFilterList.size

override fun onBindViewHolder(holder: CountryViewHolder, position: Int) {
holder.bindItem(countryFilterList[position], clickListener)
}

override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
var charSearch = constraint.toString()
countryFilterList = if (charSearch.isEmpty()) {
country
} else {
val resultList = ArrayList<Countries>()
for (row in country) {
if (row.Country.toLowerCase(Locale.ROOT).contains(charSearch.toLowerCase(Locale.ROOT))) {
resultList.add(row)
}
}
resultList
}
val filterResult = FilterResults()
filterResult.values = countryFilterList
return filterResult
}

override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
countryFilterList = results?.values as ArrayList<Countries>
notifyDataSetChanged()
}
}
}

class CountryViewHolder(view: View):RecyclerView.ViewHolder(view) {
val tvCountry = itemView.findViewById<TextView>(R.id.tv_country_name)
val tvTotalCase = itemView.findViewById<TextView>(R.id.tv_country_total_case)
val tvTotalRecoverd = itemView.findViewById<TextView>(R.id.tv_country_total_recovered)
val tvTotalDeath = itemView.findViewById<TextView>(R.id.tv_country_total_deaths)
val imgFlag = itemView.findViewById<ImageView>(R.id.img_flag_country)

fun bindItem(countries: Countries, clickListener: (Countries) -> Unit) {
tvCountry.text = countries.Country
val formatter: NumberFormat = DecimalFormat("#,###")
tvTotalCase.text = formatter.format(countries.TotalConfirmed.toDouble())
tvTotalRecoverd.text = formatter.format(countries.TotalRecovered.toDouble())
tvTotalDeath.text = formatter.format(countries.TotalRecovered.toDouble())
Glide.with(itemView.context).load("https://www.countryflags.io/" + countries.CountryCode + "/flat/16.png").into(imgFlag)

itemView.setOnClickListener {
clickListener(countries)
}
}
}
}

Setelah kita mensetting adapter nya kita pindah ke MainActivity, karena kita mengunakan patern MVP buat lah class MainPresenter dan Interface lalu beri nama MainService. Tambahkan kode berikut pada interface MainService

fun sequenceListener(ascending: Boolean)
fun itemCliked(country: Countries)
fun hideProgressBar()
fun showCountry(listCountries: ArrayList<Countries>)
fun showWorld(dataCovid: World)

Dan tambah kan kode berikut pada MainPresenter untuk mendapat kan data dari database

class MainPresenter(private val view: MainService) {

fun getCountry() {
val apiService = ApiClient.getClient()
apiService.getAllCountry().enqueue(object : Callback<AllCountries> {
override fun onResponse(call: Call<AllCountries>, response: Response<AllCountries>) {
view.hideProgressBar()
if (response.body() != null) {
response.body()!!.Global.let { view.showWorld(it) }
response.body()!!.Countries.let { view.showCountry(it) }
} else {
view.hideProgressBar()
}
}

override fun onFailure(call: Call<AllCountries>, t: Throwable) {
t.message
}

})
}
}

Beri akses kepada MainService aagar bisa digunakan didalam MainActivity. Caranya adalah menambahkan kode berikut. Tambah kan kode berikut untuk menampil kan data didalam class MainActivity

class MainActivity : AppCompatActivity(), MainService {

Dengan itu kita bisa mengimplementasi kan fungsi di dalama MainService

private val mainPresenter = MainPresenter(this)
private lateinit var countryAdapter: CountryAdapter
private var ascending = true

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

mainPresenter.getCountry()
btn_sequence.setOnClickListener {
sequenceListener(ascending)
ascending = !ascending
}

search_view.setOnQueryTextListener(object : androidx.appcompat.widget.SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}

override fun onQueryTextChange(newText: String?): Boolean {
countryAdapter.filter.filter(newText)
return false
}
})

swipe_refresh.setOnRefreshListener {
mainPresenter.getCountry()
swipe_refresh.isRefreshing = false
}
}

override fun sequenceListener(ascending: Boolean) {
rv_country.apply {
layoutManager = LinearLayoutManager(this@MainActivity)
setHasFixedSize(true)

if (ascending) {
(layoutManager as LinearLayoutManager).reverseLayout = true
(layoutManager as LinearLayoutManager).stackFromEnd = true
Toast.makeText(this@MainActivity, "Z-A", Toast.LENGTH_SHORT).show()
} else {
(layoutManager as LinearLayoutManager).reverseLayout = true
(layoutManager as LinearLayoutManager).stackFromEnd = true
Toast.makeText(this@MainActivity, "A-Z", Toast.LENGTH_SHORT).show()
}
adapter = countryAdapter
}
}

override fun itemCliked(country: Countries) {
val intent = Intent(this, ChartCountryActivity::class.java)
intent.putExtra(ChartCountryActivity.EXTRA_COUNTRY, country.Country)
intent.putExtra(ChartCountryActivity.EXTRA_LASTEST_UPDATE, country.Date)
intent.putExtra(ChartCountryActivity.EXTRA_NEW_DEATH, country.NewDeaths)
intent.putExtra(ChartCountryActivity.EXTRA_NEW_CONFIRMED, country.NewConfirmed)
intent.putExtra(ChartCountryActivity.EXTRA_NEW_RECOVERED, country.NewRecovered)
intent.putExtra(ChartCountryActivity.EXTRA_TOTAL_CONFIRMED, country.TotalConfirmed)
intent.putExtra(ChartCountryActivity.EXTRA_TOTAL_DEATH, country.TotalDeaths)
intent.putExtra(ChartCountryActivity.EXTRA_TOTAL_RECOVERED, country.TotalRecovered)
intent.putExtra(ChartCountryActivity.EXTRA_COUNTRY_CODE, country.CountryCode)
startActivity(intent)
}

override fun hideProgressBar() {
progress_bar.visibility = View.GONE
}

override fun showCountry(listCountries: ArrayList<Countries>) {
rv_country.apply {
layoutManager = LinearLayoutManager(this@MainActivity)
setHasFixedSize(true)
countryAdapter = CountryAdapter(listCountries) {
itemCliked(it)
}
adapter = countryAdapter
}
}

override fun showWorld(dataCovid: World) {
val formatter: NumberFormat = DecimalFormat("#,##")
tv_confirmed_globe.text = formatter.format(dataCovid.TotalConfirmed.toDouble())
tv_deaths_globe.text = formatter.format(dataCovid.TotalDeaths.toDouble())
tv_recovered_globe.text = formatter.format(dataCovid.TotalRecovered.toDouble())
}

Setelah itu kita pindah ke ChartCountryActivity sekali lagi karena kita menggunakan MVP tambahkan class ChartCountryPresenter dan Interface ChartCountryService. Tambahkan function showCountry dan loadImage pada ChartCountryService

fun showCountry(dataCovid: List<InfoCountry>)
fun loadImage()

Lalu tambahkan kode berikut untuk mendapat kan setiap negara

class ChartCountryPresenter(val view: ChartCountryService) {

fun getCountry(dataCountry: String) {
val apiService = ApiClient.getClient()
apiService.getInfoService(dataCountry).enqueue(object : Callback<List<InfoCountry>> {
override fun onResponse(call: Call<List<InfoCountry>>, response: Response<List<InfoCountry>>) {
if (response.body() != null) {
response.body()!!.let { view.showCountry(it) }
}
}

override fun onFailure(call: Call<List<InfoCountry>>, t: Throwable) {
t.message
}
})
}
}

Lalu tambahkan kode berikut untuk menampilkan data yg sudah kita ambil dari ChartCountryAdapter

class ChartCountryActivity : AppCompatActivity(), ChartCountryService {

private lateinit var sharedPreferences: SharedPreferences
private var sharedPrefFile = "kotlinsharedpreferences"
private var dayCases = ArrayList<String>()
private val chartCountryPresenter = ChartCountryPresenter(this)
private lateinit var dataFlag: String
private lateinit var dataCountry: String

companion object {
const val EXTRA_COUNTRY = "country"
const val EXTRA_LASTEST_UPDATE = "date"
const val EXTRA_NEW_DEATH = "new_death"
const val EXTRA_NEW_CONFIRMED = "new_confirmed"
const val EXTRA_NEW_RECOVERED = "new_recovered"
const val EXTRA_TOTAL_CONFIRMED = "total_confirmed"
const val EXTRA_TOTAL_DEATH = "total_death"
const val EXTRA_TOTAL_RECOVERED = "total_recovered"
const val EXTRA_COUNTRY_CODE = "code"

}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chart_country)

sharedPreferences = this.getSharedPreferences(sharedPrefFile, Context.MODE_PRIVATE)

val country = intent.getStringExtra(EXTRA_COUNTRY)
val date = intent.getStringExtra(EXTRA_LASTEST_UPDATE)
val newDeath = intent.getStringExtra(EXTRA_NEW_DEATH)
val newConfirmed = intent.getStringExtra(EXTRA_NEW_CONFIRMED)
val newReovered = intent.getStringExtra(EXTRA_NEW_RECOVERED)
val totalConfirmed = intent.getStringExtra(EXTRA_TOTAL_CONFIRMED)
val totalDeath = intent.getStringExtra(EXTRA_TOTAL_DEATH)
val totalRecovered = intent.getStringExtra(EXTRA_TOTAL_RECOVERED)
val countryCode = intent.getStringExtra(EXTRA_COUNTRY_CODE)

val formatter: NumberFormat = DecimalFormat("#,###")
tv_country_chart.text = country
tv_curent.text = date
tv_total_confirmed_current.text = formatter.format(totalConfirmed.toDouble())
tv_new_confirmed_current.text = formatter.format(newConfirmed.toDouble())
tv_total_recovered_current.text = formatter.format(totalRecovered.toDouble())
tv_new_recovered_current.text = formatter.format(newReovered.toDouble())
tv_total_deaths_current.text = formatter.format(totalDeath.toDouble())
tv_new_deaths_current.text = formatter.format(newDeath.toDouble())

val editor: SharedPreferences.Editor = sharedPreferences.edit()
editor.putString(country, country)
editor.apply()
editor.commit()

val saveDataCountry = sharedPreferences.getString(country, country)
val saveCountryFlag = sharedPreferences.getString(countryCode, countryCode)
dataCountry = saveDataCountry.toString()
dataFlag = saveCountryFlag.toString() + "/flat/64.png"

chartCountryPresenter.getCountry(dataCountry)

if (saveCountryFlag != null) {
loadImage()
} else {
Toast.makeText(this, "Image not found", Toast.LENGTH_SHORT).show()
}
}

override fun showCountry(dataCovid: List<InfoCountry>) {
val barEntries1: ArrayList<BarEntry> = ArrayList()
val barEntries2: ArrayList<BarEntry> = ArrayList()
val barEntries3: ArrayList<BarEntry> = ArrayList()
val barEntries4: ArrayList<BarEntry> = ArrayList()
var i = 0

while (i < dataCovid.size ?: 0) {
for (s in dataCovid) {
val barEntry1 = BarEntry(i.toFloat(), s.Confirmed.toFloat())
val barEntry2 = BarEntry(i.toFloat(), s.Deaths.toFloat())
val barEntry3 = BarEntry(i.toFloat(), s.Recovered.toFloat())
val barEntry4 = BarEntry(i.toFloat(), s.Active.toFloat())

val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:SS'Z'")
val outputFormat = SimpleDateFormat("dd-MM-yyyy")
val date: Date? = inputFormat.parse(s.Date)
val formattedDate: String = outputFormat.format(date!!)
dayCases.add(formattedDate)

barEntries1.add(barEntry1)
barEntries2.add(barEntry2)
barEntries3.add(barEntry3)
barEntries4.add(barEntry4)

i++
}
}

val xAxis: XAxis = chart_view.xAxis
xAxis.valueFormatter = IndexAxisValueFormatter(dayCases)
chart_view.axisLeft.axisMinimum = 0f
xAxis.position = XAxis.XAxisPosition.BOTTOM
xAxis.granularity = 1f
xAxis.setCenterAxisLabels(true)
xAxis.isGranularityEnabled = true

val barDataSet1 = BarDataSet(barEntries1, "Confirmed")
val barDataSet2 = BarDataSet(barEntries2, "Deaths")
val barDataSet3 = BarDataSet(barEntries3, "Recovered")
val barDataSet4 = BarDataSet(barEntries4, "Active")

barDataSet1.setColor(Color.parseColor("#F44336"))
barDataSet2.setColor(Color.parseColor("#FFEB3B"))
barDataSet3.setColor(Color.parseColor("#03DAC5"))
barDataSet4.setColor(Color.parseColor("#2196F3"))

val data = BarData(barDataSet1, barDataSet2, barDataSet3, barDataSet4)
chart_view.data = data

val barSpace = 0.02f
val groupSpace = 0.3f
val groupCount = 4f

data.barWidth = 0.15f
chart_view.invalidate()
chart_view.setNoDataTextColor(android.R.color.black)
chart_view.setTouchEnabled(true)
chart_view.description.isEnabled = false

chart_view.xAxis.axisMinimum = 0f
chart_view.setVisibleXRangeMaximum(0f + chart_view.barData.getGroupWidth(groupSpace, barSpace) * groupCount)
chart_view.groupBars(0f, groupSpace, barSpace)
}

override fun loadImage() {
Glide.with(this).load("https://www.countryflags.io/$dataFlag").into(img_flag_chart)
}
}

Dan tambahkan kode berikut supaya kita bisa mengakses internet

<uses-permission android:name="android.permission.INTERNET"/>

Begitulah cara membuat aplikasi Covid-19

--

--