ziyat akhsani
9 min readAug 8, 2020

--

Make COVID — 19 App with Kotlin

Assalamualaikum Warahmatullahi Wabarakatuh

Hallo, pada kesempatan kali ini saya akan membuat tutorial tentang aplikasi COVID-19 menggunakan kotlin.

oke langsung aja kita ke tools yang akan kita butuhkan nantinya.

jadi tool yang digunakan adalah:

  • Android Studio
  • Emulator
  • Jaringan

hal pertama yang harus dilakukan adalah membuat project baru, pilih type “empty activity”

create new project

Setelah itu, beri nama project kalian contohnya “Covid-19"

configure your project

setelah selesai, langkah selanjutnya adalah menambahkan library di gradle, yang kita butuhkan adalah android material, retrofit, gson converter, swipe refresh layout, circle image view, glide, card view, dan yang terakhir android chart setelah di tambahkan baru kita klik Sync Now.

Adding libraries for the project

langkah selanjutnya adalah menambahkan atribute-atribute yang dibutuhkan agar dapat mempersimple code kita. Pertama masuk ke bagian res -> values

  • kemudian tambahkan di bagian strings.xml
  • lalu tambahkan juga di bagian colors.xml

Setelah selesai dengan package values selanjutnya kita beralih ke package drawable disini kita akan menambahkan untuk source background, background header, search box.

Caranya klik kanan di package Drawable, klik new, klik Drawable Resource File.

kemudian beri nama seperti contoh di bawah.

bg.blue.xml
bg_header_gray.xml
box_search_country.xml

4. ic_sequence kalo yang ini kita tambahin icon, caranya klik kanan package drawable, klik new, klik vector asset, dan cari clip art yg namanya compare arrows, warnanya hitam ya lalu finish

setelah semua bahan bahan untuk layout nya sudah ada, sekarang kita coding buat tampilan yg akan di gunakan pada saat aplikasi berjalan di package layout nya.

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”
android:background=”#ffff”
tools:context=”.MainActivity”>

<TextView
android:id=”@+id/txt_title”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_marginTop=”@dimen/dp8"
android:layout_marginEnd=”@dimen/dp8"
android:layout_marginStart=”@dimen/dp8"
android:textSize=”@dimen/sp20"
android:textStyle=”bold”
android:textColor=”@color/colorPrimaryDark”
android:text=”@string/app_name”
/>

<LinearLayout
android:id=”@+id/lay_search”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:layout_below=”@+id/txt_title”
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=”match_parent”
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_below=”@+id/lay_search”
android:orientation=”horizontal”
android:layout_marginEnd=”@dimen/dp8"
android:layout_marginStart=”@dimen/dp8"
android:background=”@drawable/bg_blue”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”>

<LinearLayout
style=”@style/activityMain_linear”>

<TextView
android:text=”Confirmed”
style=”@style/activityMain_txt_name”/>

<TextView
android:id=”@+id/txt_confirmed_globe”
style=”@style/activityMain_txt_value”
android:text=”12.000.000" />
</LinearLayout>

<LinearLayout
style=”@style/activityMain_linear”>

<TextView
android:text=”Recovered”
style=”@style/activityMain_txt_name”/>

<TextView
android:id=”@+id/txt_recovered_globe”
style=”@style/activityMain_txt_value”
android:text=”12.000.000" />
</LinearLayout>

<LinearLayout
style=”@style/activityMain_linear”>

<TextView
android:text=”Mokad”
style=”@style/activityMain_txt_name”/>

<TextView
android:id=”@+id/txt_death_globe”
style=”@style/activityMain_txt_value”
android:text=”12.000.000" />
</LinearLayout>

</LinearLayout>

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

<TextView
android:text=”Countries”
style=”@style/activityMain_txt” />

<TextView
android:text=”Cases”
style=”@style/activityMain_txt” />

<TextView
android:text=”Recovered”
style=”@style/activityMain_txt” />

<TextView
android:text=”Mokad”
style=”@style/activityMain_txt” />

</LinearLayout>

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

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

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

</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

</RelativeLayout>

Kemudian,kita buat terlebih dahulu activity baru untuk Chart Country nya, dengan cara klik kanan di folder covid19 -> new -> Activity -> Empty Activity buat dengan nama ChartCountryActivity dengan begitu maka otomatis akan dibuatkan juga layout nya dengan nama activity_chart_country.xml di dalam package layout

Sekarang kita langsung menuju layout dari activity_chart_country.xml nya aja untuk membuat tampilan yg kita ingin tampilkan dari ChartCountryActivity.

activity_chart_country.xml

<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”
tools:context=”.ChartCountryActivity”>

<! — region kumpulan card →
<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=”@dimen/dp8">

<! — — SLIDE 1 →
<LinearLayout
style=”@style/activityChart_ll_parrent”
tools:ignore=”NestedWeights”>

<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=”NestedWeights” />

<androidx.cardview.widget.CardView
style=”@style/activityChart_cardview”>

<LinearLayout
style=”@style/activityChart_cardview_ll”>

<TextView
android:id=”@+id/txt_country_chart”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:gravity=”center”
android:text=”Country Name”
android:textColor=”@color/colorPrimaryDark”
android:textSize=”@dimen/sp20"
android:textStyle=”bold” />

<TextView
android:id=”@+id/txt_current”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:gravity=”center”
android:text=”CURRENTLY”
android:textSize=”@dimen/sp12"
android:textStyle=”bold” />

</LinearLayout>

</androidx.cardview.widget.CardView>

</LinearLayout>

<! — — SLIDE 2 →
<LinearLayout
style=”@style/activityChart_ll_parrent”
tools:ignore=”NestedWeights”>

<androidx.cardview.widget.CardView
style=”@style/activityChart_cardview”
app:cardBackgroundColor=”@color/orange”>

<LinearLayout
style=”@style/activityChart_cardview_ll”>

<TextView
style=”@style/activityChart_txt_name”
android:text=”Total Confirmed”
android:textColor=”@android:color/white”/>

<TextView
android:id=”@+id/txt_total_confirmed_current”
style=”@style/activityChart_txt_value”
android:textColor=”@android:color/white”/>

</LinearLayout>

</androidx.cardview.widget.CardView>

<androidx.cardview.widget.CardView
style=”@style/activityChart_cardview”
app:cardBackgroundColor=”@color/orange_gray”>

<LinearLayout
style=”@style/activityChart_cardview_ll”>

<TextView
style=”@style/activityChart_txt_name”
android:text=”New Confirmed”
android:textColor=”@android:color/white”/>

<TextView
android:id=”@+id/txt_new_confirmed_current”
style=”@style/activityChart_txt_value”
android:textColor=”@android:color/white”/>

</LinearLayout>

</androidx.cardview.widget.CardView>

</LinearLayout>

<! — — SLIDE 3 →
<LinearLayout
style=”@style/activityChart_ll_parrent”
tools:ignore=”NestedWeights”>

<androidx.cardview.widget.CardView
style=”@style/activityChart_cardview”
app:cardBackgroundColor=”@color/yellow”>

<LinearLayout
style=”@style/activityChart_cardview_ll”>

<TextView
style=”@style/activityChart_txt_name”
android:text=”Total Deaths”
android:textColor=”@color/red”/>

<TextView
android:id=”@+id/txt_total_deaths_current”
style=”@style/activityChart_txt_value”
android:textColor=”@color/red”/>

</LinearLayout>

</androidx.cardview.widget.CardView>

<androidx.cardview.widget.CardView
style=”@style/activityChart_cardview”
app:cardBackgroundColor=”@color/yellow_gray”>

<LinearLayout
style=”@style/activityChart_cardview_ll”>

<TextView
style=”@style/activityChart_txt_name”
android:text=”New Deaths”
android:textColor=”@color/red”/>

<TextView
android:id=”@+id/txt_new_deaths_current”
style=”@style/activityChart_txt_value”
android:textColor=”@color/red”/>

</LinearLayout>

</androidx.cardview.widget.CardView>

</LinearLayout>

<! — — SLIDE 4 →
<LinearLayout
style=”@style/activityChart_ll_parrent”
tools:ignore=”NestedWeights”>

<androidx.cardview.widget.CardView
style=”@style/activityChart_cardview”
app:cardBackgroundColor=”@color/colorAccent”>

<LinearLayout
style=”@style/activityChart_cardview_ll”>

<TextView
style=”@style/activityChart_txt_name”
android:text=”Total Recovered”
android:textColor=”@color/red”/>

<TextView
android:id=”@+id/txt_total_recovered_current”
style=”@style/activityChart_txt_value”
android:textColor=”@android:color/white”/>

</LinearLayout>

</androidx.cardview.widget.CardView>

<androidx.cardview.widget.CardView
style=”@style/activityChart_cardview”
app:cardBackgroundColor=”@color/blue_gray”>

<LinearLayout
style=”@style/activityChart_cardview_ll”>

<TextView
style=”@style/activityChart_txt_name”
android:text=”New Recovered”
android:textColor=”@color/red”/>

<TextView
android:id=”@+id/txt_new_recovered_current”
style=”@style/activityChart_txt_value”
android:textColor=”@android:color/white”/>

</LinearLayout>

</androidx.cardview.widget.CardView>

</LinearLayout>

</LinearLayout>

<! — — END SLIDE →
<LinearLayout
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:layout_margin=”@dimen/dp4"
android:layout_weight=”1"
android:orientation=”horizontal”>

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

</LinearLayout>

</LinearLayout>

Selanjutnya kita buat layout baru untuk menampilkan list list negara, klik kanan di package layout, klik new, klik new resource file kita buat dengan nama list_country.xml setelah itu baru kita coding untuk tampilannya.

list_country.xml

<LinearLayout
style=”@style/lc_laylinear”
xmlns:android=”http://schemas.android.com/apk/res/android"
android:background=”@color/white”>

<LinearLayout
android:id=”@+id/lay_globe_header”
style=”@style/lc_laylinear”
android:padding=”@dimen/dp8"
android:layout_margin=”@dimen/dp8"
android:background=”@drawable/bg_header_gray”>

<de.hdodenhof.circleimageview.CircleImageView
android:id=”@+id/img_flag_country”
android:layout_width=”@dimen/dp20"
android:layout_height=”@dimen/dp20"
android:layout_marginEnd=”@dimen/dp4"
android:src=”@mipmap/ic_launcher_round”/>

<TextView
android:id=”@+id/txt_country_name”
style=”@style/lc_txt”
android:text=”@string/countries”/>

<TextView
android:id=”@+id/txt_total_cases”
style=”@style/lc_txt”
android:text=”@string/cases”/>

<TextView
android:id=”@+id/txt_total_recovered”
style=”@style/lc_txt”
android:text=”@string/recovered”/>

<TextView
android:id=”@+id/txt_total_deaths”
style=”@style/lc_txt”
android:text=”@string/deaths”/>

</LinearLayout>

</LinearLayout>

Finish untuk bagian Drawable, gradle, layout, values dan segala macem, next sekarang kita membuat End-Point dan Model Data pertama kita buat dulu package network setelah itu kita buat dua kotlin file class dengan penamaan seperti berikut:

Oke langsung kita ke ApiService.kt, ini berfungsi sebagai end-point dengan menggunakan anotasi sesuai keperluan dan situasi dari webservice yang dituju dan disini saya buat 2 endpoint yang masing masing meggunakan anotasi @GET yaitu ApiService dan InfoService

Setelah itu langsung ke Model.kt, berfungi sebagai Plain Old Java Object(POJO) nya, penulisannya harus sama seperti yg ada di API ya, jagan typo karena klo typo ga akan bisa kebaca nantinya, berikut code nya

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

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

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

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

CountryAdapter

Setelah itu kita membuat kelas Adapter bernama CountryAdapter.kt fungsi adapter digunakan sebagai pengontrol sebuah data yg didapatkan dan di masukan ke Recycler View nanti, Cara buat nya seperti membuat class kotlin biasa, disini saya memasukan Adapter saya kedalam package adapter yg sudah dibuat agar terlihat rapih seperti ini

kemudian membuat constructor di dalam CountryAdapter

Sekarang pasti terdapat error, karena kita belum mengimplementasikan metode dari kelas yang telah kita extend. maka kita perlu meng-implement member terlebih dahulu, Maka setelah di implement kita akan punya 4 method, setelah itu kita buat variable baru dengan nama countryFilterList

setelah itu kita isi 4 method yang udah kita implement tadi

onCreateViewHolder
digunakan untuk meng-inflate atau menerapkan operasi yang telah di buat kedalam layout model.

getItemCount
digunakan untuk mengetahui panjang/banyak data(size) guna kebutuhan looping.

onBindViewHolder
digunakan untuk memposisikan widget pada layout model.

getFilter
digunakan untuk memberikan fungsi filter, pada project ini berdasarkan tipe data character.

Pastinya masih error, karna kita belum membuat class ViewHolder sebagai penghubung variable yang baru kita buat dengan widget-widget pada model layout.

MainActivity

Sekarang kita lanjut ke MainActivity.kt, kita akan membuat metode untuk menampilkan list negara pada recyclerview kita buat di dalam private fun getCountry()

Lalu supaya ketika tombol ketika di klik terdapat 2 statement untuk menentuka Ascending atau Descending maka kita buatkan metode initializeViews().

class MainActivity : AppCompatActivity() {

lateinit var countryAdapter: CountryAdapter
private var ascending = true

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

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 {
getCountry()
swipe_refresh.isRefreshing = false
}
}

private 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,"A-Z",Toast.LENGTH_SHORT).show()
}else{
(layoutManager as LinearLayoutManager).reverseLayout = true
(layoutManager as LinearLayoutManager).stackFromEnd = true
Toast.makeText(this@MainActivity,"Z-A",Toast.LENGTH_SHORT).show()
}

adapter = countryAdapter
}
}private fun getCountry(){
val okHttp = OkHttpClient().newBuilder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.build()

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

val api = retrofit.create(ApiService::class.java)
api.getAllCountry().enqueue(object : Callback<AllCountries>{
override fun onFailure(call: Call<AllCountries>, t: Throwable) {
TODO("Not yet implemented")
}

override fun onResponse(call: Call<AllCountries>, response: Response<AllCountries>) {
if (response.isSuccessful){
val dataCovid = response.body()?.Global // Menampung data JSON dari object Global

val formatter: NumberFormat = DecimalFormat("#,###")
txt_confirmed_globe.text = formatter.format(dataCovid?.TotalConfirmed?.toDouble())
txt_death_globe.text = formatter.format(dataCovid?.TotalDeaths?.toDouble())
txt_recovered_globe.text = formatter.format(dataCovid?.TotalDeaths?.toDouble())

rv_country.apply {
layoutManager = LinearLayoutManager(this@MainActivity)
setHasFixedSize(true)

countryAdapter = CountryAdapter(response.body()?.Countries as ArrayList<Countries>){
itemClicked(it)
}
adapter = countryAdapter

progress_bar.visibility = View.GONE
}
}else {
progress_bar.visibility = View.GONE
handleError(this@MainActivity)
}
}

})
}

private fun handleError(context: Context) {

}

Setelah itu di bawah nya kita tambahkan metode itemClicked() supaya widget yang sebelumnya telah diatur responsive menerima click dari user sekarang kita tentukan mau dibawa kemana responnya.

private fun itemClicked(country: Countries) {
val intent = Intent(this, ChartCountryActivity::class.java)
intent.putExtra(ChartCountryActivity.EXTRA_COUNTRY, country.Country)
intent.putExtra(ChartCountryActivity.EXTRA_DATE,country.Date)
intent.putExtra(ChartCountryActivity.EXTRA_COUNTRY_CODE,country.CountryCode)

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_DEATHS,country.TotalDeaths)
intent.putExtra(ChartCountryActivity.EXTRA_TOTAL_RECOVERED,country.TotalRecovered)

startActivity(intent)

}

ChartCountryActivity

Buat variable berikut

class ChartCountryActivity : AppCompatActivity() {

private lateinit var sharedPreferences: SharedPreferences

private var sharedPrefFile = “Kotlinsharedpreferences”
private var dayCases = ArrayList<String>()

Pada class ini terdapat detail yang berisikan keterangan lebih lanjut dari negara yang dipilih. maka pertama kita perlu buat banyak dari data yang ditampilkan didapat dari intentExtra class MainActivity

companion object{
const val EXTRA_COUNTRY = “country”
const val EXTRA_DATE = “date”
const val EXTRA_COUNTRY_CODE = “country_code”

const val EXTRA_NEW_DEATH = “new_deaths”
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_DEATHS = “total_deaths”
const val EXTRA_TOTAL_RECOVERED = “total_recovered”

lateinit var dataCountry: String
lateinit var dataFlag: String
}

Lalu di bawah nya yaitu di onCreate()

Lalu di getCountry()

Jadi dalam chart ada beberapa yg harus di perhatikan juga agar chart data pada chart jelas dibaca oleh user.

BarEntries itu untuk inisialisasi Yaxis nya, pada saat di while kita melakukan looping buat mendapatkan data X dan Y, dan pada saat di barEntries.add() itu untuk menaruh data yg di dapetin dari Y dan X Axis tadi atau barChart

Kita juga menambahkan nama dan warna agar user dapat mudah membaca chart yg kita buat pada barDataSet, Text, chart.

Terakhir jangan lupa untuk menambahkan permission untuk mendapatkan izin atau akses dari android kepada aplikasi kita agar aplikasi dapat mengakses Internet yaitu dengan cara ke manifest tambahkan code berikut Di atas application

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

Setelah itu aplikasi dapat di jalankan menggunakan Emulator atau Handphone masing masing, sekian tutorial saya kali ini semoga bermanfaat, sampai bertemu di tutorial selanjutnya…

Thanks for attention!

Wassalamualaikum Warahmatullahi Wabarakatuh

--

--