├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── drawable │ │ │ │ ├── error_image.png │ │ │ │ ├── bg_rounded_edit_text.xml │ │ │ │ ├── grey_gradient.xml │ │ │ │ ├── red_gradient.xml │ │ │ │ ├── amber_gradient.xml │ │ │ │ ├── green_gradient.xml │ │ │ │ ├── edit_text_rounded.xml │ │ │ │ ├── ic_home.xml │ │ │ │ ├── ic_dot_blue.xml │ │ │ │ ├── round_red_gradient.xml │ │ │ │ ├── round_amber_gradient.xml │ │ │ │ ├── round_green_gradient.xml │ │ │ │ ├── bg_card_bottom.xml │ │ │ │ ├── ic_close.xml │ │ │ │ ├── ic_notebook.xml │ │ │ │ ├── ic_grey_search.xml │ │ │ │ ├── ic_eye.xml │ │ │ │ ├── ic_search.xml │ │ │ │ ├── ic_earth.xml │ │ │ │ ├── ic_skull.xml │ │ │ │ ├── ic_heart.xml │ │ │ │ ├── ic_treatment.xml │ │ │ │ ├── ic_syringe.xml │ │ │ │ ├── ic_mask.xml │ │ │ │ ├── ic_clean.xml │ │ │ │ ├── ic_diagnosis_detail.xml │ │ │ │ ├── ic_plane.xml │ │ │ │ ├── ic_record.xml │ │ │ │ ├── ic_symptoms.xml │ │ │ │ ├── ic_transmitted.xml │ │ │ │ ├── ic_sneeze.xml │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ ├── ic_aircraft.xml │ │ │ │ ├── ic_hands.xml │ │ │ │ └── ic_bacteria.xml │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── values │ │ │ │ ├── preloaded_fonts.xml │ │ │ │ ├── styles.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── themes.xml │ │ │ │ └── font_certs.xml │ │ │ ├── anim │ │ │ │ ├── slide_in_left.xml │ │ │ │ ├── slide_in_right.xml │ │ │ │ ├── slide_out_left.xml │ │ │ │ ├── slide_out_right.xml │ │ │ │ ├── exit_to_left.xml │ │ │ │ ├── enter_from_left.xml │ │ │ │ ├── enter_from_right.xml │ │ │ │ ├── exit_to_right.xml │ │ │ │ ├── screen_splash_fade_out.xml │ │ │ │ └── scale_in.xml │ │ │ ├── font │ │ │ │ ├── nunito_sans_extrabold.xml │ │ │ │ └── nunito_sans_semibold.xml │ │ │ ├── navigation │ │ │ │ ├── tips.xml │ │ │ │ ├── country.xml │ │ │ │ └── main.xml │ │ │ ├── menu │ │ │ │ └── bottom_nav_bar.xml │ │ │ ├── layout │ │ │ │ ├── activity_detail.xml │ │ │ │ ├── activity_main.xml │ │ │ │ ├── activity_tips.xml │ │ │ │ ├── activity_country.xml │ │ │ │ ├── empty_search.xml │ │ │ │ ├── item_travel.xml │ │ │ │ ├── item_transmitted.xml │ │ │ │ ├── item_mask.xml │ │ │ │ ├── item_symptoms.xml │ │ │ │ ├── item_coranaviruses.xml │ │ │ │ ├── item_diagnosis.xml │ │ │ │ ├── item_vaccine.xml │ │ │ │ ├── item_prevent.xml │ │ │ │ ├── item_total_death.xml │ │ │ │ ├── item_total_cases.xml │ │ │ │ ├── item_total_recovered.xml │ │ │ │ ├── fragment_detail.xml │ │ │ │ ├── fragment_country.xml │ │ │ │ └── item_list.xml │ │ │ └── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ ├── assets │ │ │ └── fonts │ │ │ │ ├── NunitoSans-Black.ttf │ │ │ │ ├── NunitoSans-Bold.ttf │ │ │ │ ├── NunitoSans-Light.ttf │ │ │ │ ├── NunitoSans-Regular.ttf │ │ │ │ ├── NunitoSans-ExtraBold.ttf │ │ │ │ ├── NunitoSans-ExtraLight.ttf │ │ │ │ └── NunitoSans-SemiBold.ttf │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── covidtracker │ │ │ │ ├── data │ │ │ │ ├── model │ │ │ │ │ ├── ErrorResponse.kt │ │ │ │ │ ├── CountryWiseCase.kt │ │ │ │ │ ├── WorldStats.kt │ │ │ │ │ └── CountryStat.kt │ │ │ │ ├── ApiClient.kt │ │ │ │ └── api │ │ │ │ │ └── ServiceProvider.kt │ │ │ │ ├── di │ │ │ │ ├── appModule.kt │ │ │ │ ├── NetworkModule.kt │ │ │ │ ├── RepositoryModule.kt │ │ │ │ └── ViewModelModule.kt │ │ │ │ ├── util │ │ │ │ ├── Constants.kt │ │ │ │ ├── ResultWrapper.kt │ │ │ │ └── CrashHandler.kt │ │ │ │ ├── extensions │ │ │ │ ├── NetworkHandlerExtensions.kt │ │ │ │ ├── AdapterExtensions.kt │ │ │ │ ├── FragmentExtensions.kt │ │ │ │ └── ViewExtensions.kt │ │ │ │ └── ui │ │ │ │ ├── home │ │ │ │ ├── HomeRepository.kt │ │ │ │ ├── HomeViewModel.kt │ │ │ │ └── HomeFragment.kt │ │ │ │ ├── detail │ │ │ │ ├── DetailActivity.kt │ │ │ │ └── DetailFragment.kt │ │ │ │ ├── country │ │ │ │ ├── CountryRepository.kt │ │ │ │ ├── CountryViewModel.kt │ │ │ │ └── CountryFragment.kt │ │ │ │ ├── CovidApp.kt │ │ │ │ ├── MainActivity.kt │ │ │ │ ├── adapter │ │ │ │ └── CountryWiseAdapter.kt │ │ │ │ └── tips │ │ │ │ └── TipsFragment.kt │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── example │ │ │ └── covidtracker │ │ │ └── ExampleUnitTest.kt │ └── androidTest │ │ └── java │ │ └── com │ │ └── example │ │ └── covidtracker │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .idea ├── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── misc.xml ├── runConfigurations.xml └── gradle.xml ├── .gitignore ├── README.md ├── gradle.properties ├── versions.gradle ├── gradlew.bat └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name='CovidTracker' 2 | include ':app' 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickand/CovidTracker/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/drawable/error_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickand/CovidTracker/HEAD/app/src/main/res/drawable/error_image.png -------------------------------------------------------------------------------- /app/src/main/assets/fonts/NunitoSans-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickand/CovidTracker/HEAD/app/src/main/assets/fonts/NunitoSans-Black.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/NunitoSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickand/CovidTracker/HEAD/app/src/main/assets/fonts/NunitoSans-Bold.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/NunitoSans-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickand/CovidTracker/HEAD/app/src/main/assets/fonts/NunitoSans-Light.ttf -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickand/CovidTracker/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickand/CovidTracker/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickand/CovidTracker/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickand/CovidTracker/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/assets/fonts/NunitoSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickand/CovidTracker/HEAD/app/src/main/assets/fonts/NunitoSans-Regular.ttf -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickand/CovidTracker/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/assets/fonts/NunitoSans-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickand/CovidTracker/HEAD/app/src/main/assets/fonts/NunitoSans-ExtraBold.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/NunitoSans-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickand/CovidTracker/HEAD/app/src/main/assets/fonts/NunitoSans-ExtraLight.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/NunitoSans-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickand/CovidTracker/HEAD/app/src/main/assets/fonts/NunitoSans-SemiBold.ttf -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/data/model/ErrorResponse.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.data.model 2 | 3 | data class ErrorResponse(val message: String) -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_rounded_edit_text.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/di/appModule.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.di 2 | 3 | import com.google.gson.Gson 4 | import org.koin.dsl.module 5 | 6 | var appModule = module { 7 | // Gson creation is heavy. Keep an instance 8 | single { Gson() } 9 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/grey_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Mar 25 00:57:28 COT 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/data/model/CountryWiseCase.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.data.model 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | data class CountryWiseCase( 6 | 7 | @SerializedName("countries_stat") val countryStats: List 8 | ) -------------------------------------------------------------------------------- /app/src/main/res/values/preloaded_fonts.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | @font/nunito_sans_extrabold 5 | @font/nunito_sans_semibold 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/red_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/amber_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/green_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_out_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_out_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/di/NetworkModule.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.di 2 | 3 | import com.example.covidtracker.data.api.getApiService 4 | import com.example.covidtracker.data.api.getGlideUrl 5 | import org.koin.dsl.module 6 | 7 | val networkModule = module { 8 | single { getApiService() } 9 | single { getGlideUrl() } 10 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/exit_to_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/anim/enter_from_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/anim/enter_from_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/anim/exit_to_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/edit_text_rounded.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_home.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/anim/screen_splash_fade_out.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_dot_blue.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/round_red_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/di/RepositoryModule.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.di 2 | 3 | import com.example.covidtracker.ui.country.CountryRepository 4 | import com.example.covidtracker.ui.home.HomeRepository 5 | import org.koin.dsl.module 6 | 7 | val repositoryModule = module { 8 | single { HomeRepository(get()) } 9 | single { CountryRepository(get()) } 10 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/round_amber_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/round_green_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/data/model/WorldStats.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.data.model 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | data class WorldStats( 6 | 7 | @SerializedName("total_cases") val totalCases: String, 8 | @SerializedName("total_deaths") val totalDeath: String, 9 | @SerializedName("total_recovered") val totalRecovered: String 10 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/util/Constants.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.util 2 | 3 | import com.example.covidtracker.BuildConfig 4 | 5 | object Constants{ 6 | 7 | const val BASE_URL = "https://coronavirus-monitor.p.rapidapi.com/" 8 | const val API_KEY = BuildConfig.API_KEY 9 | const val MASK_INSTRUCTIONS_URL = BASE_URL + "coronavirus/random_masks_usage_instructions.php" 10 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/scale_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/di/ViewModelModule.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.di 2 | 3 | import com.example.covidtracker.ui.country.CountryViewModel 4 | import com.example.covidtracker.ui.home.HomeViewModel 5 | import org.koin.android.viewmodel.dsl.viewModel 6 | import org.koin.dsl.module 7 | 8 | val viewModelModule = module { 9 | viewModel { HomeViewModel(get()) } 10 | viewModel { CountryViewModel(get()) } 11 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_card_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_close.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/font/nunito_sans_extrabold.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/font/nunito_sans_semibold.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/util/ResultWrapper.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.util 2 | 3 | import com.example.covidtracker.data.model.ErrorResponse 4 | 5 | sealed class ResultWrapper { 6 | data class Success(val value: T): ResultWrapper() 7 | data class GenericError(val code: Int? = null, val error: ErrorResponse? = null): ResultWrapper() 8 | data class Error(val exception: String?) : ResultWrapper() 9 | } -------------------------------------------------------------------------------- /app/src/test/java/com/example/covidtracker/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/data/ApiClient.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.data 2 | 3 | import com.example.covidtracker.data.model.CountryWiseCase 4 | import com.example.covidtracker.data.model.WorldStats 5 | import retrofit2.http.GET 6 | 7 | interface ApiClient { 8 | 9 | @GET("coronavirus/cases_by_country.php") 10 | suspend fun getCountryWiseCases(): CountryWiseCase 11 | 12 | @GET("coronavirus/worldstat.php") 13 | suspend fun getWorldStats(): WorldStats 14 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/data/model/CountryStat.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.data.model 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | data class CountryStat( 6 | 7 | @SerializedName("country_name") val countryName: String, 8 | @SerializedName("cases") val totalCases: String, 9 | @SerializedName("deaths") val totalDeaths: String, 10 | @SerializedName("total_recovered") val totalRecovered: String, 11 | @SerializedName("new_cases") val newCases: String 12 | ) -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notebook.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_grey_search.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_eye.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/navigation/tips.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/extensions/NetworkHandlerExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.extensions 2 | 3 | import com.example.covidtracker.util.ResultWrapper 4 | 5 | suspend fun safeApiCall( 6 | call: suspend () -> T, 7 | onSuccess: (ResultWrapper.Success) -> Unit, 8 | onFailure: (ResultWrapper.Error) -> Unit 9 | ) { 10 | runCatching { 11 | val response = call() 12 | onSuccess.invoke(ResultWrapper.Success(response)) 13 | }.onFailure { 14 | it.printStackTrace() 15 | onFailure.invoke(ResultWrapper.Error(it.message)) 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/res/navigation/country.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_earth.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_skull.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/ui/home/HomeRepository.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.ui.home 2 | 3 | import com.example.covidtracker.data.ApiClient 4 | import com.example.covidtracker.data.model.WorldStats 5 | import com.example.covidtracker.extensions.safeApiCall 6 | import com.example.covidtracker.util.ResultWrapper 7 | 8 | class HomeRepository(private val service: ApiClient) { 9 | 10 | suspend fun getWorldStats(): ResultWrapper? { 11 | var networkResult: ResultWrapper? = null 12 | 13 | safeApiCall( { service.getWorldStats() }, 14 | { networkResult = it }, 15 | { networkResult = it } 16 | ) 17 | 18 | return networkResult 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_heart.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Coronavirus Tracker - CovidTracker 2 | 3 | 4 | Coronavirus Tracker for Android which shows worldwide data of confirmed cases, recovered cases and death cases. You can also get country-wise data. The data is provided by https://rapidapi.com/astsiatsko/api/coronavirus-monitor 5 | 6 |
7 | 8 | [](https://drive.google.com/open?id=1P9r5KtLmkPFUrvddWKWgBiyYx8a2X8l1) 9 | 10 | ![coronavirus_tracker_banner](https://user-images.githubusercontent.com/4821464/77816551-80b2ed00-7091-11ea-89a5-24f3b0e3f128.png) 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/ui/detail/DetailActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.ui.detail 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AppCompatActivity 5 | import com.example.covidtracker.R 6 | import com.example.covidtracker.extensions.addFragment 7 | 8 | class DetailActivity : AppCompatActivity() { 9 | 10 | override fun onCreate(savedInstanceState: Bundle?) { 11 | super.onCreate(savedInstanceState) 12 | setContentView(R.layout.activity_detail) 13 | 14 | initDetail() 15 | } 16 | 17 | private fun initDetail() { 18 | intent.getBundleExtra(DetailFragment.DETAIL)?.let { DetailFragment(it) }?.let { 19 | addFragment(supportFragmentManager, R.id.fragmentContainer, 20 | it 21 | ) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/covidtracker/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.example.covidtracker", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/res/menu/bottom_nav_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 16 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/ui/country/CountryRepository.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.ui.country 2 | 3 | import com.example.covidtracker.data.ApiClient 4 | import com.example.covidtracker.data.model.CountryWiseCase 5 | import com.example.covidtracker.data.model.WorldStats 6 | import com.example.covidtracker.extensions.safeApiCall 7 | import com.example.covidtracker.util.ResultWrapper 8 | import kotlinx.coroutines.Dispatchers 9 | import kotlinx.coroutines.withContext 10 | 11 | class CountryRepository(private val service: ApiClient) { 12 | 13 | suspend fun getCountryWiseCases(): ResultWrapper? { 14 | var networkResult: ResultWrapper? = null 15 | 16 | safeApiCall( { service.getCountryWiseCases() }, 17 | { networkResult = it }, 18 | { networkResult = it } 19 | ) 20 | 21 | return networkResult 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/ui/CovidApp.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.ui 2 | 3 | import android.app.Application 4 | import com.example.covidtracker.di.appModule 5 | import com.example.covidtracker.di.networkModule 6 | import com.example.covidtracker.di.repositoryModule 7 | import com.example.covidtracker.di.viewModelModule 8 | import org.koin.android.ext.koin.androidContext 9 | import org.koin.core.context.startKoin 10 | 11 | class CovidApp : Application() { 12 | 13 | companion object { 14 | lateinit var mApplication: CovidApp 15 | private set 16 | } 17 | 18 | override fun onCreate() { 19 | super.onCreate() 20 | mApplication = this 21 | 22 | startKoin { 23 | androidContext(this@CovidApp) 24 | modules( 25 | listOf( 26 | appModule, 27 | viewModelModule, 28 | networkModule, 29 | repositoryModule 30 | ) 31 | ) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2dp 5 | 4dp 6 | 8dp 7 | 10dp 8 | 12dp 9 | 15dp 10 | 16dp 11 | 25dp 12 | 24dp 13 | 32dp 14 | 40dp 15 | 48dp 16 | 56dp 17 | 64dp 18 | 19 | 20 | 2sp 21 | 4sp 22 | 8sp 23 | 12sp 24 | 16sp 25 | 18sp 26 | 20sp 27 | 24sp 28 | 32sp 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/util/CrashHandler.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.util 2 | 3 | import android.app.AlarmManager 4 | import android.app.PendingIntent 5 | import android.content.Context 6 | import android.content.Intent 7 | import android.util.Log 8 | import com.example.covidtracker.ui.MainActivity 9 | import kotlin.system.exitProcess 10 | 11 | class CrashHandler(private val context: Context) : Thread.UncaughtExceptionHandler { 12 | private val TAG = "CrashHandler" 13 | 14 | override fun uncaughtException(t: Thread?, e: Throwable?) { 15 | Log.e(TAG, "Intercepted uncaught exception", e) 16 | val intent = Intent(context, MainActivity::class.java).apply { 17 | putExtra(EXTRA_CRASH, true) 18 | addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or 19 | Intent.FLAG_ACTIVITY_CLEAR_TASK or 20 | Intent.FLAG_ACTIVITY_NEW_TASK 21 | ) 22 | } 23 | val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT) 24 | 25 | val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager 26 | alarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pendingIntent) 27 | exitProcess(2) 28 | } 29 | 30 | companion object { 31 | const val EXTRA_CRASH = "com.example.covidtracker.CrashHandler.EXTRA_CRASH" 32 | } 33 | } -------------------------------------------------------------------------------- /versions.gradle: -------------------------------------------------------------------------------- 1 | ext.deps = [:] 2 | def versions = [:] 3 | 4 | versions.support = "1.0.2" 5 | versions.lifecycle = "2.0.0" 6 | versions.koin = "1.0.2" 7 | versions.retrofit = "2.4.0" 8 | versions.okhttp_logging_interceptor = "3.9.0" 9 | versions.glide = "4.9.0" 10 | versions.android_gradle_plugin = '3.5.0' 11 | versions.kotlin = "1.3.21" 12 | versions.moshi_kotlin = "1.7.0" 13 | versions.navigation = "2.1.0-alpha02" 14 | versions.constraint_layout = "2.0.0-alpha2" 15 | versions.coroutines = "1.0.1" 16 | versions.coroutine_adapter = "0.9.2" 17 | versions.rxjava = "2.2.2" 18 | versions.room = "1.0.0" 19 | versions.rx_android = "2.1.0" 20 | versions.rx_room = "1.1.1" 21 | versions.junit = "4.12" 22 | versions.mockito = "2.0.0-RC1" 23 | versions.assertj = "3.11.1" 24 | versions.location = "16.0.0" 25 | versions.gson = "2.8.5" 26 | versions.gson_converter = "2.4.0" 27 | versions.butterknife = "10.1.0" 28 | versions.exoplayer = "2.10.5" 29 | versions.bugfender = "1.1.7" 30 | versions.work_version = "2.1.0" 31 | 32 | def build_versions = [:] 33 | build_versions.min_sdk = 26 34 | build_versions.target_sdk = 28 35 | build_versions.build_tools = "28.0.3" 36 | ext.build_versions = build_versions 37 | 38 | ext.deps 39 | 40 | ext.versions = versions 41 | 42 | def addRepos(RepositoryHandler handler) { 43 | handler.google() 44 | handler.jcenter() 45 | handler.maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } 46 | } 47 | 48 | ext.addRepos = this.&addRepos 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/extensions/AdapterExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.extensions 2 | 3 | import com.example.covidtracker.data.model.CountryStat 4 | import com.example.covidtracker.ui.adapter.CountryWiseAdapter 5 | 6 | fun CountryWiseAdapter.search(list: MutableList, originalList: MutableList, query: String) { 7 | list.clear() 8 | list.addAll(originalList) 9 | 10 | if (query.isNotEmpty()) { 11 | var index = 0 12 | 13 | while (index < list.size) { 14 | if (list[index].countryName.toLowerCase().contains(query.toLowerCase()).not()) { 15 | list.removeAt(index) 16 | index-- 17 | } 18 | index++ 19 | } 20 | } 21 | 22 | notifyDataSetChanged() 23 | } 24 | 25 | fun filterColombia(list: List, newList: MutableList, 26 | originalList: MutableList) { 27 | var colIndex = -1 28 | var colItem: CountryStat? = null 29 | 30 | for (index in list.indices) { 31 | if (list[index].countryName == "Colombia") { 32 | colIndex = index 33 | colItem = list[index] 34 | break 35 | } 36 | } 37 | 38 | if (colIndex != -1 && colItem != null) { 39 | newList.add(0, colItem) 40 | newList.removeAt(colIndex + 1) 41 | 42 | originalList.add(0, colItem) 43 | originalList.removeAt(colIndex + 1) 44 | } 45 | } -------------------------------------------------------------------------------- /app/src/main/res/navigation/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 16 | 20 | 21 | 26 | 27 | 28 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 19 | 20 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #555656 4 | #000000 5 | #FFC000 6 | 7 | #000000 8 | #4D000000 9 | #80000000 10 | #B3000000 11 | #607D8B 12 | #212121 13 | #555656 14 | #9F9F9F 15 | #4D9F9F9F 16 | #C9C9C9 17 | #F4F5F5 18 | #FFFFFF 19 | #4DFFFFFF 20 | #B3FFFFFF 21 | #E6FFFFFF 22 | #E20F33 23 | #EF5350 24 | 25 | 26 | #FF1744 27 | #B71C1C 28 | 29 | 30 | #FFC400 31 | #FF6F00 32 | 33 | 34 | #00E676 35 | #1B5E20 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_tips.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 20 | 21 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_country.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 21 | 22 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/extensions/FragmentExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.extensions 2 | 3 | import android.os.Bundle 4 | import androidx.annotation.IdRes 5 | import androidx.fragment.app.Fragment 6 | import androidx.fragment.app.FragmentManager 7 | import androidx.navigation.fragment.findNavController 8 | import androidx.navigation.navOptions 9 | import com.example.covidtracker.R 10 | import com.example.covidtracker.ui.detail.DetailFragment 11 | 12 | fun Fragment.selectTab(destId: Int, args: Bundle? = null) = findNavController() 13 | .navigate(destId, args, navOptions { 14 | popUpTo(findNavController().graph.startDestination) { inclusive = true } 15 | }) 16 | 17 | /** 18 | * Adds a [Fragment] in the backstack in the [FragmentManager] 19 | * 20 | * @param fragment the fragment to be added. 21 | */ 22 | fun addFragment( 23 | supportFragmentManager: FragmentManager, @IdRes idResContainer: Int, 24 | fragment: Fragment 25 | ) { 26 | val transaction = supportFragmentManager.beginTransaction() 27 | if (fragment is DetailFragment) { 28 | transaction.add(idResContainer, fragment) 29 | transaction.commit() 30 | } 31 | } 32 | 33 | /** 34 | * Replace a [Fragment] in the backstack in the [FragmentManager] 35 | * 36 | * @param fragment the fragment to be added. 37 | */ 38 | fun replaceFragment( 39 | supportFragmentManager: FragmentManager, @IdRes idResContainer: Int, 40 | fragment: Fragment 41 | ) { 42 | val transaction = supportFragmentManager.beginTransaction() 43 | transaction.replace(idResContainer, fragment) 44 | transaction.addToBackStack(null) 45 | transaction.commit() 46 | } -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 16 | 17 | 31 | 32 | 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/data/api/ServiceProvider.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.data.api 2 | 3 | import com.bumptech.glide.load.model.GlideUrl 4 | import com.bumptech.glide.load.model.LazyHeaders 5 | import com.example.covidtracker.data.ApiClient 6 | import com.example.covidtracker.util.Constants 7 | import okhttp3.Interceptor 8 | import okhttp3.OkHttpClient 9 | import okhttp3.logging.HttpLoggingInterceptor 10 | import retrofit2.Retrofit 11 | import retrofit2.converter.gson.GsonConverterFactory 12 | 13 | fun getOkHttpClient(): OkHttpClient { 14 | 15 | val interceptor = Interceptor { chain -> 16 | val request = 17 | chain.request().newBuilder() 18 | .addHeader("x-rapidapi-host", "coronavirus-monitor.p.rapidapi.com") 19 | .addHeader("x-rapidapi-key", Constants.API_KEY) 20 | 21 | val actualRequest = request.build() 22 | chain.proceed(actualRequest) 23 | } 24 | 25 | return HttpLoggingInterceptor().run { 26 | level = HttpLoggingInterceptor.Level.BODY 27 | OkHttpClient.Builder().addInterceptor(interceptor).build() 28 | } 29 | } 30 | 31 | fun getApiService(): ApiClient { 32 | return Retrofit.Builder() 33 | .baseUrl(Constants.BASE_URL) 34 | .addConverterFactory(GsonConverterFactory.create()) 35 | .client(getOkHttpClient()) 36 | .build().run { 37 | create(ApiClient::class.java) 38 | } 39 | } 40 | 41 | fun getGlideUrl(): GlideUrl { 42 | return GlideUrl( 43 | Constants.MASK_INSTRUCTIONS_URL, LazyHeaders.Builder() 44 | .addHeader("x-rapidapi-host", "coronavirus-monitor.p.rapidapi.com") 45 | .addHeader("x-rapidapi-key", Constants.API_KEY) 46 | .build() 47 | ) 48 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/ui/detail/DetailFragment.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.ui.detail 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import com.example.covidtracker.R 9 | import kotlinx.android.synthetic.main.fragment_detail.* 10 | 11 | class DetailFragment(var bundle: Bundle) : Fragment() { 12 | 13 | companion object { 14 | const val DETAIL = "detail" 15 | const val IMAGE = "image" 16 | const val TITLE = "title" 17 | const val DESCRIPTION = "description" 18 | } 19 | 20 | private var image: Int = 0 21 | private lateinit var title: String 22 | private lateinit var description: String 23 | 24 | override fun onCreate(savedInstanceState: Bundle?) { 25 | super.onCreate(savedInstanceState) 26 | if (!bundle.isEmpty) { 27 | bundle = requireActivity().intent.getBundleExtra(DETAIL)!! 28 | image = bundle.getInt(IMAGE) 29 | title = bundle.getString(TITLE).orEmpty() 30 | description = bundle.getString(DESCRIPTION).orEmpty() 31 | } 32 | } 33 | 34 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, 35 | savedInstanceState: Bundle?): View? { 36 | return inflater.inflate(R.layout.fragment_detail, container, false) 37 | } 38 | 39 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 40 | super.onViewCreated(view, savedInstanceState) 41 | 42 | iconDetail.setImageResource(image) 43 | titleDetail.text = title 44 | descriptionDetail.text = description 45 | 46 | closeImage.setOnClickListener { 47 | requireActivity().finish() 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/ui/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.ui 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import android.view.Window 6 | import androidx.appcompat.app.AppCompatActivity 7 | import com.example.covidtracker.R 8 | import com.example.covidtracker.extensions.selectTab 9 | import com.google.android.material.bottomnavigation.BottomNavigationView 10 | import kotlinx.android.synthetic.main.activity_main.* 11 | 12 | class MainActivity : AppCompatActivity() { 13 | 14 | override fun onCreate(savedInstanceState: Bundle?) { 15 | super.onCreate(savedInstanceState) 16 | requestWindowFeature(Window.FEATURE_NO_TITLE) 17 | setContentView(R.layout.activity_main) 18 | 19 | bottom_navigation.setOnNavigationItemSelectedListener { item -> 20 | when (item.itemId) { 21 | R.id.action_home -> { 22 | initHome() 23 | } 24 | R.id.action_tip -> { 25 | initTips() 26 | } 27 | R.id.action_worldwide -> { 28 | initCountry() 29 | } 30 | } 31 | true 32 | } 33 | } 34 | 35 | private fun initCountry() { 36 | navigationFragment.selectTab(R.id.countryFragment) 37 | } 38 | 39 | private fun initTips() { 40 | navigationFragment.selectTab(R.id.tipsFragment) 41 | } 42 | 43 | private fun initHome() { 44 | navigationFragment.selectTab(R.id.homeFragment) 45 | } 46 | 47 | override fun onBackPressed() { 48 | val bottomNavigationView = 49 | findViewById(R.id.bottom_navigation) as BottomNavigationView 50 | val selectedItemId = bottomNavigationView.selectedItemId 51 | if (R.id.action_home != selectedItemId || R.id.action_home == selectedItemId) { 52 | finish() 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/res/layout/empty_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 20 | 21 | 32 | 33 | 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_treatment.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 39 | 42 | 45 | 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/ui/home/HomeViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.ui.home 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.MutableLiveData 5 | import androidx.lifecycle.ViewModel 6 | import com.example.covidtracker.data.model.WorldStats 7 | import com.example.covidtracker.util.ResultWrapper 8 | import kotlinx.coroutines.* 9 | import kotlin.coroutines.CoroutineContext 10 | 11 | class HomeViewModel(private val homeRepository: HomeRepository) : ViewModel(), CoroutineScope { 12 | 13 | private var job: Job = Job() 14 | 15 | override val coroutineContext: CoroutineContext 16 | get() = Dispatchers.Main + job 17 | 18 | private val uiModel = MutableLiveData() 19 | val model: LiveData 20 | get() { 21 | if (uiModel.value == null) refresh() 22 | return uiModel 23 | } 24 | 25 | private var worldStat: WorldStats? = null 26 | private var errorWorldStats: String? = null 27 | 28 | private val _errorLiveData = MutableLiveData() 29 | val errorLiveData: LiveData 30 | get() = _errorLiveData 31 | 32 | sealed class UiModel { 33 | object Loading : UiModel() 34 | class Content(val worldStat: WorldStats?) : UiModel() 35 | object ShowUi : UiModel() 36 | } 37 | 38 | init { 39 | job = SupervisorJob() 40 | } 41 | 42 | private fun refresh() { 43 | uiModel.value = UiModel.ShowUi 44 | } 45 | 46 | private fun destroyScope() { 47 | job.cancel() 48 | } 49 | 50 | fun getWorldStats() { 51 | launch { 52 | uiModel.value = UiModel.Loading 53 | 54 | when (val worldStatsResponse = homeRepository.getWorldStats()) { 55 | is ResultWrapper.GenericError -> { 56 | val responseData = worldStatsResponse.error?.message 57 | errorWorldStats = responseData 58 | } 59 | is ResultWrapper.Success -> { 60 | val responseData = worldStatsResponse.value 61 | worldStat = responseData 62 | } 63 | } 64 | 65 | uiModel.value = UiModel.Content(worldStat) 66 | } 67 | } 68 | 69 | override fun onCleared() { 70 | destroyScope() 71 | super.onCleared() 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/item_travel.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 16 | 17 | 26 | 27 | 32 | 33 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_transmitted.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 16 | 17 | 26 | 27 | 32 | 33 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_mask.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 16 | 17 | 27 | 28 | 33 | 34 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_symptoms.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 17 | 18 | 27 | 28 | 33 | 34 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_coranaviruses.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 17 | 18 | 27 | 28 | 33 | 34 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/ui/adapter/CountryWiseAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.ui.adapter 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import androidx.recyclerview.widget.RecyclerView 7 | import com.example.covidtracker.R 8 | import com.example.covidtracker.data.model.CountryStat 9 | import com.example.covidtracker.extensions.filterColombia 10 | import kotlinx.android.synthetic.main.item_list.view.* 11 | 12 | class CountryWiseAdapter( 13 | private val list: MutableList, 14 | private val listener: OnEvent) : RecyclerView.Adapter() { 15 | 16 | private var originalList = mutableListOf() 17 | 18 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { 19 | val view = LayoutInflater.from(parent.context).inflate(R.layout.item_list, parent, false) 20 | return CountryWiseViewHolder(view) 21 | } 22 | 23 | fun addData(list: List) { 24 | this.list.addAll(list) 25 | originalList.addAll(list) 26 | filterColombia(list.toMutableList(), this.list, originalList) 27 | notifyDataSetChanged() 28 | } 29 | 30 | fun getList(): MutableList { 31 | return list 32 | } 33 | 34 | fun getOriginalList(): MutableList { 35 | return originalList 36 | } 37 | 38 | fun clear() { 39 | list.clear() 40 | originalList.clear() 41 | notifyDataSetChanged() 42 | } 43 | 44 | override fun getItemCount(): Int = list.size 45 | 46 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { 47 | if (holder is CountryWiseViewHolder) 48 | holder.bind(list[position]) 49 | } 50 | 51 | inner class CountryWiseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 52 | 53 | fun bind(countryStat: CountryStat) { 54 | itemView.apply { 55 | countryName.text = countryStat.countryName 56 | newCasesCount.text = countryStat.newCases 57 | confirmedCount.text = countryStat.totalCases 58 | recoveredCount.text = countryStat.totalRecovered 59 | deathCount.text = countryStat.totalDeaths 60 | } 61 | } 62 | } 63 | 64 | interface OnEvent { 65 | fun logEvent(query: String) 66 | } 67 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/item_diagnosis.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 16 | 17 | 27 | 28 | 33 | 34 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_vaccine.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 16 | 17 | 27 | 28 | 33 | 34 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_syringe.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_prevent.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 16 | 17 | 26 | 27 | 32 | 33 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/ui/country/CountryViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.ui.country 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.MutableLiveData 5 | import androidx.lifecycle.ViewModel 6 | import com.example.covidtracker.data.model.CountryStat 7 | import com.example.covidtracker.data.model.CountryWiseCase 8 | import com.example.covidtracker.util.ResultWrapper 9 | import kotlinx.coroutines.* 10 | import kotlin.coroutines.CoroutineContext 11 | 12 | class CountryViewModel(private val countryRepository: CountryRepository) : ViewModel(), 13 | CoroutineScope { 14 | 15 | private var job: Job = Job() 16 | 17 | private var countryWiseCases: CountryWiseCase? = null 18 | private var errorCountryWiseCases: String? = null 19 | 20 | private val countryWiseCasesList = MutableLiveData?>() 21 | val countryWiseCasesResponse: LiveData?> 22 | get() = countryWiseCasesList 23 | 24 | override val coroutineContext: CoroutineContext 25 | get() = Dispatchers.Main + job 26 | 27 | private val uiModel = MutableLiveData() 28 | val model: LiveData 29 | get() { 30 | if (uiModel.value == null) refresh() 31 | return uiModel 32 | } 33 | 34 | sealed class UiModel { 35 | object Loading : UiModel() 36 | class Content(val countryStat: CountryWiseCase?) : UiModel() 37 | class Navigation(val countryStat: CountryStat) : UiModel() 38 | object ShowUi : UiModel() 39 | } 40 | 41 | init { 42 | job = SupervisorJob() 43 | } 44 | 45 | private fun refresh() { 46 | uiModel.value = UiModel.ShowUi 47 | } 48 | 49 | private fun destroyScope() { 50 | job.cancel() 51 | } 52 | 53 | fun getCountryWiseCases() { 54 | launch { 55 | uiModel.value = UiModel.Loading 56 | 57 | when (val countryResponse = countryRepository.getCountryWiseCases()) { 58 | is ResultWrapper.GenericError -> { 59 | val responseData = countryResponse.error?.message 60 | errorCountryWiseCases = responseData 61 | } 62 | is ResultWrapper.Success -> { 63 | val responseData = countryResponse.value 64 | countryWiseCases = responseData 65 | } 66 | } 67 | 68 | uiModel.value = UiModel.Content(countryWiseCases) 69 | } 70 | } 71 | 72 | override fun onCleared() { 73 | destroyScope() 74 | super.onCleared() 75 | } 76 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/item_total_death.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 20 | 21 | 26 | 27 | 41 | 42 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_total_cases.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 20 | 21 | 26 | 27 | 41 | 42 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_total_recovered.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 20 | 21 | 26 | 27 | 41 | 42 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_mask.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_clean.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/values/font_certs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | @array/com_google_android_gms_fonts_certs_dev 5 | @array/com_google_android_gms_fonts_certs_prod 6 | 7 | 8 | 9 | MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs= 10 | 11 | 12 | 13 | 14 | MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_diagnosis_detail.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 39 | 42 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 22 | 23 | 32 | 33 | 43 | 44 | 57 | 58 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/ui/country/CountryFragment.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.ui.country 2 | 3 | import android.content.Context 4 | import android.os.Bundle 5 | import android.text.Editable 6 | import android.text.TextWatcher 7 | import android.util.Log 8 | import android.view.LayoutInflater 9 | import android.view.View 10 | import android.view.ViewGroup 11 | import android.view.inputmethod.InputMethodManager 12 | import android.widget.EditText 13 | import androidx.fragment.app.Fragment 14 | import androidx.lifecycle.Observer 15 | import androidx.recyclerview.widget.LinearLayoutManager 16 | import com.example.covidtracker.R 17 | import com.example.covidtracker.extensions.gone 18 | import com.example.covidtracker.extensions.search 19 | import com.example.covidtracker.extensions.visible 20 | import com.example.covidtracker.ui.adapter.CountryWiseAdapter 21 | import kotlinx.android.synthetic.main.fragment_country.* 22 | import kotlinx.android.synthetic.main.fragment_home.progressBar 23 | import org.koin.android.viewmodel.ext.android.viewModel 24 | import java.util.* 25 | 26 | 27 | class CountryFragment : Fragment(), CountryWiseAdapter.OnEvent { 28 | 29 | private val countryViewModel: CountryViewModel by viewModel() 30 | 31 | private lateinit var listAdapter: CountryWiseAdapter 32 | 33 | override fun onCreate(savedInstanceState: Bundle?) { 34 | super.onCreate(savedInstanceState) 35 | 36 | countryViewModel.model.observe(this, Observer(::updateUi)) 37 | } 38 | 39 | override fun onCreateView( 40 | inflater: LayoutInflater, container: ViewGroup?, 41 | savedInstanceState: Bundle? 42 | ): View? { 43 | val view = inflater.inflate(R.layout.fragment_country, container, false) 44 | 45 | listAdapter = CountryWiseAdapter(mutableListOf(), this) 46 | 47 | return view 48 | } 49 | 50 | private fun updateUi(model: CountryViewModel.UiModel) { 51 | when (model) { 52 | is CountryViewModel.UiModel.Loading -> { 53 | progressBar.visible() 54 | } 55 | is CountryViewModel.UiModel.Content -> { 56 | progressBar.gone() 57 | 58 | model.countryStat?.countryStats?.let { listAdapter.addData(it) } 59 | 60 | setupRecyclerView() 61 | 62 | performSearch() 63 | 64 | Log.d("TAG", "RESPONSE: " + model.countryStat.toString()) 65 | } 66 | is CountryViewModel.UiModel.Navigation -> { 67 | 68 | } 69 | CountryViewModel.UiModel.ShowUi -> { 70 | countryViewModel.getCountryWiseCases() 71 | } 72 | } 73 | } 74 | 75 | private fun setupRecyclerView() { 76 | countryWiseRecyclerView.apply { 77 | layoutManager = LinearLayoutManager(requireContext()) 78 | adapter = listAdapter 79 | } 80 | } 81 | 82 | private fun performSearch() { 83 | searchEditText.requestFocus() 84 | searchEditText.addTextChangedListener(object : TextWatcher { 85 | override fun afterTextChanged(s: Editable?) { 86 | } 87 | 88 | override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { 89 | } 90 | 91 | override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { 92 | listAdapter.search(listAdapter.getList(), listAdapter.getOriginalList(), s.toString()) 93 | } 94 | 95 | }) 96 | } 97 | 98 | private fun hideSoftKeyboard(input: EditText) { 99 | val imm: InputMethodManager = Objects.requireNonNull(activity) 100 | ?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager 101 | imm.hideSoftInputFromWindow(input.windowToken, 0) 102 | } 103 | 104 | override fun logEvent(query: String) { 105 | 106 | } 107 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/extensions/ViewExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.extensions 2 | 3 | import android.graphics.Outline 4 | import android.graphics.drawable.Drawable 5 | import android.view.View 6 | import android.view.ViewOutlineProvider 7 | import android.widget.ImageView 8 | import com.bumptech.glide.Glide 9 | import com.bumptech.glide.load.DataSource 10 | import com.bumptech.glide.load.engine.GlideException 11 | import com.bumptech.glide.load.model.GlideUrl 12 | import com.bumptech.glide.load.resource.bitmap.CenterCrop 13 | import com.bumptech.glide.load.resource.bitmap.RoundedCorners 14 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions 15 | import com.bumptech.glide.request.RequestListener 16 | import com.bumptech.glide.request.RequestOptions 17 | import com.bumptech.glide.request.target.Target 18 | import com.example.covidtracker.R 19 | 20 | fun View.visible() { 21 | visibility = View.VISIBLE 22 | } 23 | 24 | fun View.invisible() { 25 | visibility = View.INVISIBLE 26 | } 27 | 28 | fun View.gone() { 29 | visibility = View.GONE 30 | } 31 | 32 | fun ImageView.loadGlideUrl(url: GlideUrl) { 33 | Glide.with(context) 34 | .load(url) 35 | .transition(DrawableTransitionOptions.withCrossFade()) 36 | .listener(object : RequestListener { 37 | override fun onLoadFailed( 38 | e: GlideException?, 39 | model: Any?, 40 | target: Target?, 41 | isFirstResource: Boolean 42 | ): Boolean { 43 | this@loadGlideUrl.scaleType = ImageView.ScaleType.FIT_XY 44 | return false 45 | } 46 | 47 | override fun onResourceReady( 48 | resource: Drawable?, 49 | model: Any?, 50 | target: Target?, 51 | dataSource: DataSource?, 52 | isFirstResource: Boolean 53 | ): Boolean { 54 | return false 55 | } 56 | 57 | }) 58 | .apply( 59 | RequestOptions() 60 | .placeholder(R.color.white_70_percent) 61 | .error(R.drawable.error_image) 62 | ) 63 | .into(this) 64 | } 65 | 66 | fun ImageView.loadUrl(url: String) { 67 | Glide.with(context) 68 | .load(url) 69 | .transition(DrawableTransitionOptions.withCrossFade()) 70 | .listener(object : RequestListener { 71 | override fun onLoadFailed( 72 | e: GlideException?, 73 | model: Any?, 74 | target: Target?, 75 | isFirstResource: Boolean 76 | ): Boolean { 77 | this@loadUrl.scaleType = ImageView.ScaleType.CENTER 78 | return false 79 | } 80 | 81 | override fun onResourceReady( 82 | resource: Drawable?, 83 | model: Any?, 84 | target: Target?, 85 | dataSource: DataSource?, 86 | isFirstResource: Boolean 87 | ): Boolean { 88 | return false 89 | } 90 | 91 | }) 92 | .apply( 93 | RequestOptions() 94 | .placeholder(R.color.gray) 95 | .error(R.drawable.ic_virus) 96 | ) 97 | .into(this) 98 | } 99 | 100 | fun View.setRoundCorners(radiusRes: Int) { 101 | this.clipToOutline = true 102 | this.outlineProvider = object : ViewOutlineProvider() { 103 | override fun getOutline(view: View?, outline: Outline?) { 104 | outline?.setRoundRect( 105 | 0, 106 | 0, 107 | view!!.width, 108 | view.height, 109 | view.context.resources.getDimension(radiusRes) 110 | ) 111 | } 112 | } 113 | this.clipToOutline = true 114 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_plane.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 39 | 42 | 43 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | xmlns:android 17 | 18 | ^$ 19 | 20 | 21 | 22 |
23 |
24 | 25 | 26 | 27 | xmlns:.* 28 | 29 | ^$ 30 | 31 | 32 | BY_NAME 33 | 34 |
35 |
36 | 37 | 38 | 39 | .*:id 40 | 41 | http://schemas.android.com/apk/res/android 42 | 43 | 44 | 45 |
46 |
47 | 48 | 49 | 50 | .*:name 51 | 52 | http://schemas.android.com/apk/res/android 53 | 54 | 55 | 56 |
57 |
58 | 59 | 60 | 61 | name 62 | 63 | ^$ 64 | 65 | 66 | 67 |
68 |
69 | 70 | 71 | 72 | style 73 | 74 | ^$ 75 | 76 | 77 | 78 |
79 |
80 | 81 | 82 | 83 | .* 84 | 85 | ^$ 86 | 87 | 88 | BY_NAME 89 | 90 |
91 |
92 | 93 | 94 | 95 | .* 96 | 97 | http://schemas.android.com/apk/res/android 98 | 99 | 100 | ANDROID_ATTRIBUTE_ORDER 101 | 102 |
103 |
104 | 105 | 106 | 107 | .* 108 | 109 | .* 110 | 111 | 112 | BY_NAME 113 | 114 |
115 |
116 |
117 |
118 | 119 | 121 |
122 |
-------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | apply plugin: 'kotlin-kapt' 5 | apply plugin: 'androidx.navigation.safeargs' 6 | 7 | android { 8 | compileSdkVersion 29 9 | buildToolsVersion "29.0.3" 10 | 11 | defaultConfig { 12 | applicationId "com.example.covidtracker" 13 | minSdkVersion 21 14 | targetSdkVersion 29 15 | versionCode 1 16 | versionName "1.0" 17 | 18 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 19 | 20 | buildConfigField("String", "API_KEY", "\"$COVID_API_KEY\"") 21 | } 22 | 23 | buildTypes { 24 | release { 25 | minifyEnabled false 26 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 27 | } 28 | } 29 | 30 | compileOptions { 31 | sourceCompatibility = 1.8 32 | targetCompatibility = 1.8 33 | } 34 | 35 | kotlinOptions { 36 | jvmTarget = JavaVersion.VERSION_1_8.toString() 37 | } 38 | } 39 | 40 | ext { 41 | supportVersion = '28.0.0' 42 | retrofitVersion = '2.5.0' 43 | lifecycle_version = '1.1.1' 44 | glideVersion = '4.8.0' 45 | } 46 | 47 | dependencies { 48 | implementation fileTree(dir: 'libs', include: ['*.jar']) 49 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 50 | implementation 'androidx.appcompat:appcompat:1.1.0' 51 | implementation 'androidx.core:core-ktx:1.2.0' 52 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 53 | testImplementation 'junit:junit:4.12' 54 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 55 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 56 | 57 | implementation "androidx.lifecycle:lifecycle-livedata:2.2.0" 58 | implementation "androidx.lifecycle:lifecycle-livedata-core:2.2.0" 59 | implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" 60 | 61 | implementation 'androidx.core:core-ktx:1.2.0' 62 | 63 | //Retrofit 64 | implementation "com.squareup.retrofit2:retrofit:$retrofitVersion" 65 | implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.1' 66 | 67 | //Paser JSON 68 | implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion" 69 | implementation 'com.google.code.gson:gson:2.8.2' 70 | 71 | //Logging HTTP 72 | implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0' 73 | 74 | // ViewModel and LiveData 75 | implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' 76 | 77 | //CardView 78 | implementation 'androidx.cardview:cardview:1.0.0' 79 | 80 | //RecyclerView 81 | implementation 'androidx.recyclerview:recyclerview:1.0.0' 82 | 83 | //Support Design 84 | implementation 'com.google.android.material:material:1.0.0' 85 | 86 | //Glide 87 | implementation "com.github.bumptech.glide:glide:$glideVersion" 88 | annotationProcessor "com.github.bumptech.glide:compiler:$glideVersion" 89 | 90 | //Coroutines 91 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.1' 92 | implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2' 93 | 94 | //Navigation 95 | implementation "androidx.navigation:navigation-fragment-ktx:2.2.1" 96 | implementation "androidx.navigation:navigation-ui-ktx:2.2.1" 97 | 98 | //Room 99 | implementation 'androidx.room:room-runtime:2.2.5' 100 | kapt 'androidx.room:room-compiler:2.2.5' 101 | implementation 'androidx.room:room-rxjava2:2.0.0' 102 | 103 | //Lottie 104 | implementation 'com.airbnb.android:lottie:3.0.7' 105 | 106 | implementation 'com.loopj.android:android-async-http:1.4.8' 107 | 108 | //Koin 109 | implementation 'org.koin:koin-android:2.0.1' 110 | implementation 'org.koin:koin-android-viewmodel:2.0.1' 111 | implementation 'org.koin:koin-android-scope:2.0.1' 112 | 113 | //Moshi 114 | implementation "com.squareup.retrofit2:converter-moshi:$versions.retrofit" 115 | implementation "com.squareup.moshi:moshi-kotlin:$versions.moshi_kotlin" 116 | } 117 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_record.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_symptoms.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 39 | 42 | 45 | 48 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_transmitted.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 39 | 42 | 45 | 48 | 51 | 54 | 57 | 60 | 63 | 66 | 69 | 72 | 75 | 78 | 81 | 84 | 87 | 90 | 91 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_country.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 30 | 31 | 47 | 48 | 63 | 64 | 79 | 80 | 89 | 90 | 99 | 100 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sneeze.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/ui/home/HomeFragment.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.ui.home 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import android.text.Spannable 7 | import android.text.SpannableString 8 | import android.text.style.ForegroundColorSpan 9 | import android.view.LayoutInflater 10 | import android.view.View 11 | import android.view.ViewGroup 12 | import androidx.core.content.ContextCompat 13 | import androidx.fragment.app.Fragment 14 | import androidx.lifecycle.Observer 15 | import com.example.covidtracker.R 16 | import com.example.covidtracker.data.api.getGlideUrl 17 | import com.example.covidtracker.extensions.gone 18 | import com.example.covidtracker.extensions.loadGlideUrl 19 | import com.example.covidtracker.extensions.setRoundCorners 20 | import com.example.covidtracker.extensions.visible 21 | import com.example.covidtracker.ui.detail.DetailActivity 22 | import com.example.covidtracker.ui.detail.DetailFragment 23 | import kotlinx.android.synthetic.main.fragment_home.* 24 | import kotlinx.android.synthetic.main.item_total_cases.* 25 | import kotlinx.android.synthetic.main.item_total_death.* 26 | import kotlinx.android.synthetic.main.item_total_recovered.* 27 | import org.koin.android.viewmodel.ext.android.viewModel 28 | 29 | 30 | class HomeFragment : Fragment() { 31 | 32 | private val homeViewModel: HomeViewModel by viewModel() 33 | 34 | override fun onCreate(savedInstanceState: Bundle?) { 35 | super.onCreate(savedInstanceState) 36 | 37 | homeViewModel.model.observe(this, Observer(::updateUi)) 38 | } 39 | 40 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, 41 | savedInstanceState: Bundle?): View? { 42 | return inflater.inflate(R.layout.fragment_home, container, false) 43 | } 44 | 45 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 46 | super.onViewCreated(view, savedInstanceState) 47 | 48 | itemCoranaviruses.setOnClickListener { 49 | goToDetailActivivty( 50 | requireContext(), 51 | R.drawable.ic_bacteria, 52 | getString(R.string.what_are_coronaviruses_subtitle), 53 | getString(R.string.coronaviruses_detail)) 54 | } 55 | itemSymptoms.setOnClickListener { 56 | goToDetailActivivty( 57 | requireContext(), 58 | R.drawable.ic_symptoms, 59 | getString(R.string.what_are_the_symptoms_subtitle), 60 | getString(R.string.symptoms_detail)) 61 | } 62 | itemTransmitted.setOnClickListener { 63 | goToDetailActivivty( 64 | requireContext(), 65 | R.drawable.ic_transmitted, 66 | getString(R.string.how_is_it_transmitted), 67 | getString(R.string.transmitted_detail)) 68 | } 69 | itemPrevent.setOnClickListener { 70 | goToDetailActivivty( 71 | requireContext(), 72 | R.drawable.ic_hands, 73 | getString(R.string.how_prevent), 74 | getString(R.string.prevent_detail)) 75 | } 76 | } 77 | 78 | private fun goToDetailActivivty( 79 | context: Context, image: Int, 80 | title: String, description: String) { 81 | val intent = Intent(context, DetailActivity::class.java) 82 | val bundle = Bundle() 83 | bundle.putInt(DetailFragment.IMAGE, image) 84 | bundle.putString(DetailFragment.TITLE, title) 85 | bundle.putString(DetailFragment.DESCRIPTION, description) 86 | intent.putExtra(DetailFragment.DETAIL, bundle) 87 | startActivity(intent) 88 | } 89 | 90 | private fun loadBanner() { 91 | bannerImage.loadGlideUrl(getGlideUrl()) 92 | bannerImage.setRoundCorners(R.dimen.spacing_xs) 93 | } 94 | 95 | private fun updateUi(model: HomeViewModel.UiModel) { 96 | when (model) { 97 | is HomeViewModel.UiModel.Loading -> { 98 | progressBar.visible() 99 | } 100 | is HomeViewModel.UiModel.Content -> { 101 | progressBar.gone() 102 | 103 | loadBanner() 104 | customizeTitleApp() 105 | 106 | txtCasesSubtitle.text = model.worldStat?.totalCases 107 | txtRecoveredSubtitle.text = model.worldStat?.totalRecovered 108 | txtDeathSubtitle.text = model.worldStat?.totalDeath 109 | } 110 | HomeViewModel.UiModel.ShowUi -> { 111 | homeViewModel.getWorldStats() 112 | } 113 | } 114 | } 115 | 116 | private fun customizeTitleApp() { 117 | val spannable = SpannableString(getString(R.string.app_title)) 118 | spannable.setSpan( 119 | ForegroundColorSpan(ContextCompat.getColor(requireContext(), R.color.red)), 120 | 0, 11, 121 | Spannable.SPAN_EXCLUSIVE_EXCLUSIVE 122 | ) 123 | appTitle.text = spannable 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/covidtracker/ui/tips/TipsFragment.kt: -------------------------------------------------------------------------------- 1 | package com.example.covidtracker.ui.tips 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import android.text.Spannable 7 | import android.text.SpannableString 8 | import android.text.style.ForegroundColorSpan 9 | import android.view.LayoutInflater 10 | import android.view.View 11 | import android.view.ViewGroup 12 | import androidx.core.content.ContextCompat 13 | import androidx.fragment.app.Fragment 14 | import androidx.navigation.fragment.findNavController 15 | import com.example.covidtracker.R 16 | import com.example.covidtracker.extensions.addFragment 17 | import com.example.covidtracker.ui.detail.DetailActivity 18 | import com.example.covidtracker.ui.detail.DetailFragment 19 | import kotlinx.android.synthetic.main.fragment_home.* 20 | import kotlinx.android.synthetic.main.fragment_home.itemCoranaviruses 21 | import kotlinx.android.synthetic.main.fragment_home.itemPrevent 22 | import kotlinx.android.synthetic.main.fragment_home.itemSymptoms 23 | import kotlinx.android.synthetic.main.fragment_home.itemTransmitted 24 | import kotlinx.android.synthetic.main.fragment_home.tipsOfficersTitle 25 | import kotlinx.android.synthetic.main.fragment_tips.* 26 | 27 | class TipsFragment : Fragment() { 28 | 29 | override fun onCreate(savedInstanceState: Bundle?) { 30 | super.onCreate(savedInstanceState) 31 | } 32 | 33 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, 34 | savedInstanceState: Bundle?): View? { 35 | return inflater.inflate(R.layout.fragment_tips, container, false) 36 | } 37 | 38 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 39 | super.onViewCreated(view, savedInstanceState) 40 | customizeTitleApp() 41 | 42 | itemCoranaviruses.setOnClickListener { 43 | goToDetailActivivty( 44 | requireContext(), 45 | R.drawable.ic_bacteria, 46 | getString(R.string.what_are_coronaviruses_subtitle), 47 | getString(R.string.coronaviruses_detail)) 48 | } 49 | itemSymptoms.setOnClickListener { 50 | goToDetailActivivty( 51 | requireContext(), 52 | R.drawable.ic_symptoms, 53 | getString(R.string.what_are_the_symptoms_subtitle), 54 | getString(R.string.symptoms_detail)) 55 | } 56 | itemTransmitted.setOnClickListener { 57 | goToDetailActivivty( 58 | requireContext(), 59 | R.drawable.ic_transmitted, 60 | getString(R.string.how_is_it_transmitted), 61 | getString(R.string.transmitted_detail)) 62 | } 63 | itemPrevent.setOnClickListener { 64 | goToDetailActivivty( 65 | requireContext(), 66 | R.drawable.ic_hands, 67 | getString(R.string.how_prevent), 68 | getString(R.string.prevent_detail)) 69 | } 70 | itemWearMask.setOnClickListener { 71 | goToDetailActivivty( 72 | requireContext(), 73 | R.drawable.ic_mask_detail, 74 | getString(R.string.when_to_wear_a_mask), 75 | getString(R.string.mask_detail)) 76 | } 77 | itemDiagnosis.setOnClickListener { 78 | goToDetailActivivty( 79 | requireContext(), 80 | R.drawable.ic_diagnosis_detail, 81 | getString(R.string.diagnosis_title), 82 | getString(R.string.diagnosis_detail)) 83 | } 84 | itemTravel.setOnClickListener { 85 | goToDetailActivivty( 86 | requireContext(), 87 | R.drawable.ic_plane, 88 | getString(R.string.information_for_travelers), 89 | getString(R.string.travel_detail)) 90 | } 91 | itemVaccine.setOnClickListener { 92 | goToDetailActivivty( 93 | requireContext(), 94 | R.drawable.ic_treatment, 95 | getString(R.string.is_there_a_vaccine_medication_or_treatment), 96 | getString(R.string.treatment_detail)) 97 | } 98 | } 99 | 100 | private fun goToDetailActivivty( 101 | context: Context, image: Int, 102 | title: String, description: String) { 103 | val intent = Intent(context, DetailActivity::class.java) 104 | val bundle = Bundle() 105 | bundle.putInt(DetailFragment.IMAGE, image) 106 | bundle.putString(DetailFragment.TITLE, title) 107 | bundle.putString(DetailFragment.DESCRIPTION, description) 108 | intent.putExtra(DetailFragment.DETAIL, bundle) 109 | startActivity(intent) 110 | } 111 | 112 | private fun customizeTitleApp() { 113 | val spannable = SpannableString(getString(R.string.tips_officers)) 114 | spannable.setSpan( 115 | ForegroundColorSpan(ContextCompat.getColor(requireContext(), R.color.red)), 116 | 0, 4, 117 | Spannable.SPAN_EXCLUSIVE_EXCLUSIVE 118 | ) 119 | tipsOfficersTitle.text = spannable 120 | } 121 | } -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_aircraft.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_hands.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 39 | 42 | 45 | 48 | 51 | 54 | 57 | 60 | 63 | 64 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 22 | 23 | 35 | 36 | 46 | 47 | 59 | 60 | 72 | 73 | 82 | 83 | 98 | 99 | 108 | 109 | 121 | 122 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_bacteria.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 39 | 42 | 45 | 48 | 51 | 54 | 57 | 60 | 63 | 66 | 69 | 72 | 75 | 76 | --------------------------------------------------------------------------------