From 6541e76f92d32e2231298f6ad37e51e640643b07 Mon Sep 17 00:00:00 2001 From: wiryadev Date: Sun, 15 Aug 2021 12:23:00 +0700 Subject: [PATCH 01/18] migrate to androidX --- build.gradle | 2 + examples/android-weather-app/build.gradle | 56 ++++++++------- .../fr/ekito/myweatherapp/WeatherDAOTest.kt | 21 +++--- .../myweatherapp/WeatherRepositoryTest.kt | 14 ++-- .../ekito/myweatherapp/room_test_modules.kt | 2 +- .../fr/ekito/myweatherapp/MainApplication.kt | 6 +- .../ekito/myweatherapp/data/json/Geocode.kt | 2 - .../ekito/myweatherapp/data/json/Weather.kt | 2 - .../data/local/AndroidJsonReader.kt | 4 +- .../myweatherapp/data/room/Converters.kt | 4 +- .../myweatherapp/data/room/WeatherDAO.kt | 8 +-- .../myweatherapp/data/room/WeatherDatabase.kt | 6 +- .../myweatherapp/data/room/WeatherEntity.kt | 6 +- .../myweatherapp/di/room_datasource_module.kt | 3 +- .../util/android/FragmentActivityExt.kt | 4 +- .../myweatherapp/util/mvvm/RxViewModel.kt | 4 +- .../myweatherapp/util/mvvm/SingleLiveEvent.kt | 14 ++-- .../view/detail/DetailActivity.kt | 9 ++- .../view/detail/DetailViewModel.kt | 4 +- .../view/splash/SplashActivity.kt | 7 +- .../view/splash/SplashViewModel.kt | 2 +- .../view/weather/WeatherActivity.kt | 7 +- .../view/weather/WeatherHeaderFragment.kt | 22 +++--- .../view/weather/WeatherListFragment.kt | 30 ++++---- .../view/weather/WeatherViewModel.kt | 4 +- .../view/weather/list/WeatherListAdapter.kt | 4 +- .../src/main/res/layout/activity_detail.xml | 8 +-- .../res/layout/fragment_result_header.xml | 3 +- .../main/res/layout/fragment_result_list.xml | 2 +- .../src/main/res/menu/menu_main.xml | 2 +- .../integration/WeatherRepositoryTest.kt | 9 +-- .../fr/ekito/myweatherapp/mock/MockedData.kt | 2 +- .../mock/mvvm/DetailViewModelMockTest.kt | 12 ++-- .../mock/mvvm/SplashViewModelMockTest.kt | 8 +-- .../mvvm/WeatherHeaderViewModelMockTest.kt | 6 +- .../mock/mvvm/WeatherListViewModelMockTest.kt | 8 ++- gradle.properties | 4 ++ gradle/versions-android.gradle | 12 ++-- gradle/versions-examples.gradle | 12 ++-- gradle/versions.gradle | 10 +-- gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 72 +++++++++++-------- gradlew.bat | 18 ++--- 43 files changed, 227 insertions(+), 211 deletions(-) diff --git a/build.gradle b/build.gradle index 61b7079..cb8e5d4 100644 --- a/build.gradle +++ b/build.gradle @@ -5,6 +5,7 @@ buildscript { repositories { google() jcenter() + mavenCentral() } dependencies { // Kotlin @@ -27,6 +28,7 @@ allprojects { repositories { google() jcenter() + mavenCentral() } group = 'org.koin' diff --git a/examples/android-weather-app/build.gradle b/examples/android-weather-app/build.gradle index 11d76bd..34ae07a 100644 --- a/examples/android-weather-app/build.gradle +++ b/examples/android-weather-app/build.gradle @@ -1,7 +1,9 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-kapt' -apply plugin: 'kotlin-android-extensions' +plugins { + id 'com.android.application' + id 'kotlin-android' + id 'kotlin-kapt' + id 'kotlin-android-extensions' +} apply from: '../../gradle/versions-examples.gradle' @@ -16,7 +18,7 @@ android { versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" // used by Room, to test migrations javaCompileOptions { @@ -27,7 +29,7 @@ android { } } testOptions { - execution 'ANDROID_TEST_ORCHESTRATOR' + execution 'ANDROIDX_TEST_ORCHESTRATOR' } buildTypes { release { @@ -46,43 +48,43 @@ android { } dependencies { - // Android Support - implementation "com.android.support:appcompat-v7:$support_lib_version" - implementation "com.android.support:support-v4:$support_lib_version" - implementation "com.android.support:design:$support_lib_version" + // AndroidX + implementation "androidx.appcompat:appcompat:1.3.1" + implementation "androidx.appcompat:appcompat-resources:1.3.1" // Android Test testImplementation "junit:junit:$junit_version" testImplementation "org.mockito:mockito-inline:$mockito_version" - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestUtil 'com.android.support.test:orchestrator:1.0.2' + androidTestImplementation 'androidx.test:runner:1.4.0' + androidTestUtil 'androidx.test:orchestrator:1.4.0' - // Kotlin - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" // Anko implementation "org.jetbrains.anko:anko-commons:$anko_version" // Koin - implementation "org.koin:koin-android-viewmodel:$koin_version" - testImplementation "org.koin:koin-test:$koin_version" - androidTestImplementation "org.koin:koin-test:$koin_version" + implementation "io.insert-koin:koin-android:$koin_version" + implementation "io.insert-koin:koin-android-viewmodel:$koin_version" + testImplementation "io.insert-koin:koin-test:$koin_version" + androidTestImplementation "io.insert-koin:koin-test:$koin_version" // ViewModel and LiveData - implementation "android.arch.lifecycle:extensions:$android_arch_version" - testImplementation "android.arch.core:core-testing:$android_arch_version" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" + testImplementation "androidx.arch.core:core-testing:$arch_version" // Room - implementation "android.arch.persistence.room:runtime:$room_version" - implementation "android.arch.persistence.room:rxjava2:$room_version" - kapt "android.arch.persistence.room:compiler:$room_version" - annotationProcessor "android.arch.persistence.room:compiler:$room_version" - testImplementation "android.arch.persistence.room:testing:$room_version" + implementation "androidx.room:room-runtime:$room_version" + implementation "androidx.room:room-rxjava2:$room_version" + kapt "androidx.room:room-compiler:$room_version" + annotationProcessor "androidx.room:room-compiler:$room_version" + testImplementation "androidx.room:room-testing:$room_version" // UI - implementation "com.android.support.constraint:constraint-layout:$constraint_layout_version" + implementation 'com.google.android.material:material:1.4.0' + implementation "androidx.constraintlayout:constraintlayout:$constraint_layout_version" implementation 'com.joanzapata.iconify:android-iconify-weathericons:2.2.2' // Gson - implementation 'com.google.code.gson:gson:2.8.2' + implementation 'com.google.code.gson:gson:2.8.6' // Networking implementation "com.squareup.retrofit2:retrofit:$retrofit_version" @@ -93,7 +95,7 @@ dependencies { // Rx implementation "io.reactivex.rxjava2:rxjava:$rxjava_version" - implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' + implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' // Canary debugImplementation "com.squareup.leakcanary:leakcanary-android:$leak_canary_version" diff --git a/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/WeatherDAOTest.kt b/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/WeatherDAOTest.kt index 05fc250..b1bc3e4 100644 --- a/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/WeatherDAOTest.kt +++ b/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/WeatherDAOTest.kt @@ -1,6 +1,6 @@ package fr.ekito.myweatherapp -import android.support.test.runner.AndroidJUnit4 +import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner import fr.ekito.myweatherapp.data.WeatherDataSource import fr.ekito.myweatherapp.data.room.WeatherDAO import fr.ekito.myweatherapp.data.room.WeatherDatabase @@ -9,6 +9,7 @@ import fr.ekito.myweatherapp.domain.ext.getDailyForecasts import fr.ekito.myweatherapp.domain.ext.getLocation import junit.framework.Assert import org.junit.After +import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -16,16 +17,16 @@ import org.koin.core.context.loadKoinModules import org.koin.core.context.stopKoin import org.koin.test.KoinTest import org.koin.test.inject -import java.util.Date +import java.util.* -@RunWith(AndroidJUnit4::class) +@RunWith(AndroidJUnit4ClassRunner::class) class WeatherDAOTest : KoinTest { - val weatherDatabase: WeatherDatabase by inject() - val weatherWebDatasource: WeatherDataSource by inject() - val weatherDAO: WeatherDAO by inject() + private val weatherDatabase: WeatherDatabase by inject() + private val weatherWebDatasource: WeatherDataSource by inject() + private val weatherDAO: WeatherDAO by inject() - @Before() + @Before fun before() { loadKoinModules(roomTestModule) } @@ -48,7 +49,7 @@ class WeatherDAOTest : KoinTest { val requestedEntities = ids.map { weatherDAO.findWeatherById(it).blockingGet() } - Assert.assertEquals(entities, requestedEntities) + assertEquals(entities, requestedEntities) } @Test @@ -65,7 +66,7 @@ class WeatherDAOTest : KoinTest { val resultList = weatherDAO.findAllBy(locationTlse, dateToulouse).blockingGet() - Assert.assertEquals(weatherToulouse, resultList) + assertEquals(weatherToulouse, resultList) } @Test @@ -88,7 +89,7 @@ class WeatherDAOTest : KoinTest { val result: WeatherEntity = weatherDAO.findLatestWeather().blockingGet().first() val resultList = weatherDAO.findAllBy(result.location, result.date).blockingGet() - Assert.assertEquals(weatherToulouse, resultList) + assertEquals(weatherToulouse, resultList) } private fun getWeatherAsEntities( diff --git a/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/WeatherRepositoryTest.kt b/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/WeatherRepositoryTest.kt index c4b4fce..c2af609 100644 --- a/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/WeatherRepositoryTest.kt +++ b/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/WeatherRepositoryTest.kt @@ -1,9 +1,9 @@ package fr.ekito.myweatherapp -import android.support.test.runner.AndroidJUnit4 +import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner import fr.ekito.myweatherapp.domain.repository.DailyForecastRepository -import junit.framework.Assert import org.junit.After +import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -12,12 +12,12 @@ import org.koin.core.context.stopKoin import org.koin.test.KoinTest import org.koin.test.inject -@RunWith(AndroidJUnit4::class) +@RunWith(AndroidJUnit4ClassRunner::class) class WeatherRepositoryTest : KoinTest { private val weatherRepository: DailyForecastRepository by inject() - @Before() + @Before fun before() { loadKoinModules(roomTestModule) } @@ -31,7 +31,7 @@ class WeatherRepositoryTest : KoinTest { fun testGetDefault() { val defaultWeather = weatherRepository.getWeather().blockingGet() val defaultWeather2 = weatherRepository.getWeather().blockingGet() - Assert.assertEquals(defaultWeather, defaultWeather2) + assertEquals(defaultWeather, defaultWeather2) } @Test @@ -40,7 +40,7 @@ class WeatherRepositoryTest : KoinTest { val result = defaultWeather.first() val first = weatherRepository.getWeatherDetail(result.id).blockingGet() - Assert.assertEquals(result, first) + assertEquals(result, first) } @Test @@ -49,6 +49,6 @@ class WeatherRepositoryTest : KoinTest { weatherRepository.getWeather("London").blockingGet() val toulouse = weatherRepository.getWeather("Toulouse").blockingGet() val defaultWeather3 = weatherRepository.getWeather().blockingGet() - Assert.assertEquals(defaultWeather3, toulouse) + assertEquals(defaultWeather3, toulouse) } } \ No newline at end of file diff --git a/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/room_test_modules.kt b/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/room_test_modules.kt index b4f8bb1..d48847e 100644 --- a/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/room_test_modules.kt +++ b/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/room_test_modules.kt @@ -1,6 +1,6 @@ package fr.ekito.myweatherapp -import android.arch.persistence.room.Room +import androidx.room.Room import fr.ekito.myweatherapp.data.room.WeatherDatabase import org.koin.dsl.module diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/MainApplication.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/MainApplication.kt index 8e5049b..0198d26 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/MainApplication.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/MainApplication.kt @@ -5,6 +5,7 @@ import com.joanzapata.iconify.Iconify import com.joanzapata.iconify.fonts.WeathericonsModule import fr.ekito.myweatherapp.di.roomWeatherApp import org.koin.android.ext.koin.androidContext +import org.koin.android.ext.koin.androidFileProperties import org.koin.android.ext.koin.androidLogger import org.koin.core.context.startKoin import org.koin.core.logger.Level @@ -19,13 +20,12 @@ class MainApplication : Application() { // start Koin context startKoin { - fileProperties() androidLogger(Level.DEBUG) androidContext(this@MainApplication) + androidFileProperties() modules(roomWeatherApp) } - Iconify - .with(WeathericonsModule()) + Iconify.with(WeathericonsModule()) } } diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/json/Geocode.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/json/Geocode.kt index e803035..f64ec04 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/json/Geocode.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/json/Geocode.kt @@ -1,7 +1,5 @@ package fr.ekito.myweatherapp.data.json -import java.util.* - data class AddressComponent( val long_name: String? = null, val short_name: String? = null, diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/json/Weather.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/json/Weather.kt index 012f186..99eb962 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/json/Weather.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/json/Weather.kt @@ -1,7 +1,5 @@ package fr.ekito.myweatherapp.data.json -import java.util.* - data class Avewind( val mph: Int? = null, val kph: Int? = null, diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/local/AndroidJsonReader.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/local/AndroidJsonReader.kt index 936c223..a44c430 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/local/AndroidJsonReader.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/local/AndroidJsonReader.kt @@ -9,11 +9,11 @@ import java.io.InputStreamReader */ class AndroidJsonReader(val application: Application) : BaseReader() { - override fun getAllFiles(): List = application.assets.list("json").toList() + override fun getAllFiles(): List = application.assets.list("json")!!.toList() override fun readJsonFile(jsonFile: String): String { val buf = StringBuilder() - val json = application.assets.open("json/" + jsonFile) + val json = application.assets.open("json/$jsonFile") BufferedReader(InputStreamReader(json, "UTF-8")) .use { val list = it.lineSequence().toList() diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/Converters.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/Converters.kt index dcaa607..4d9bcc0 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/Converters.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/Converters.kt @@ -1,7 +1,7 @@ package fr.ekito.myweatherapp.data.room -import android.arch.persistence.room.TypeConverter -import java.util.* +import androidx.room.TypeConverter +import java.util.Date class Converters { @TypeConverter diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/WeatherDAO.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/WeatherDAO.kt index 13b2f07..b5cd477 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/WeatherDAO.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/WeatherDAO.kt @@ -1,10 +1,10 @@ package fr.ekito.myweatherapp.data.room -import android.arch.persistence.room.Dao -import android.arch.persistence.room.Insert -import android.arch.persistence.room.Query +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query import io.reactivex.Single -import java.util.* +import java.util.Date @Dao interface WeatherDAO { diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/WeatherDatabase.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/WeatherDatabase.kt index 75d7514..429c299 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/WeatherDatabase.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/WeatherDatabase.kt @@ -1,8 +1,8 @@ package fr.ekito.myweatherapp.data.room -import android.arch.persistence.room.Database -import android.arch.persistence.room.RoomDatabase -import android.arch.persistence.room.TypeConverters +import androidx.room.Database +import androidx.room.RoomDatabase +import androidx.room.TypeConverters @Database(entities = [WeatherEntity::class], version = 1) @TypeConverters(Converters::class) diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/WeatherEntity.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/WeatherEntity.kt index 7c15c89..311d4c1 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/WeatherEntity.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/WeatherEntity.kt @@ -1,9 +1,9 @@ package fr.ekito.myweatherapp.data.room -import android.arch.persistence.room.Entity -import android.arch.persistence.room.PrimaryKey +import androidx.room.Entity +import androidx.room.PrimaryKey import fr.ekito.myweatherapp.domain.entity.DailyForecast -import java.util.* +import java.util.Date @Entity(tableName = "weather") data class WeatherEntity( diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/di/room_datasource_module.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/di/room_datasource_module.kt index b5d9cc7..4515973 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/di/room_datasource_module.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/di/room_datasource_module.kt @@ -1,6 +1,7 @@ package fr.ekito.myweatherapp.di -import android.arch.persistence.room.Room + +import androidx.room.Room import fr.ekito.myweatherapp.data.room.WeatherDatabase import fr.ekito.myweatherapp.domain.repository.DailyForecastRepository import fr.ekito.myweatherapp.domain.repository.DailyForecastRepositoryRoomImpl diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/android/FragmentActivityExt.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/android/FragmentActivityExt.kt index f7a8740..07b9c2c 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/android/FragmentActivityExt.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/android/FragmentActivityExt.kt @@ -2,11 +2,11 @@ package fr.ekito.myweatherapp.util.android -import android.support.v4.app.FragmentActivity +import androidx.fragment.app.FragmentActivity /** * Retrieve argument from Activity intent */ fun FragmentActivity.argument(key: String) = - lazy { intent.extras[key] as? T ?: error("Intent Argument $key is missing") } + lazy { intent.extras?.get(key) as? T ?: error("Intent Argument $key is missing") } diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/mvvm/RxViewModel.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/mvvm/RxViewModel.kt index bc0b2b3..6af1028 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/mvvm/RxViewModel.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/mvvm/RxViewModel.kt @@ -1,7 +1,7 @@ package fr.ekito.myweatherapp.util.mvvm -import android.arch.lifecycle.ViewModel -import android.support.annotation.CallSuper +import androidx.annotation.CallSuper +import androidx.lifecycle.ViewModel import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/mvvm/SingleLiveEvent.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/mvvm/SingleLiveEvent.kt index b26a4c2..783b10c 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/mvvm/SingleLiveEvent.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/mvvm/SingleLiveEvent.kt @@ -1,10 +1,10 @@ package fr.ekito.myweatherapp.util.mvvm -import android.arch.lifecycle.LifecycleOwner -import android.arch.lifecycle.MutableLiveData -import android.arch.lifecycle.Observer -import android.support.annotation.MainThread import android.util.Log +import androidx.annotation.MainThread +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.Observer import java.util.concurrent.atomic.AtomicBoolean /** @@ -28,15 +28,13 @@ class SingleLiveEvent : MutableLiveData() { private val pending = AtomicBoolean(false) - @MainThread - override fun observe(owner: LifecycleOwner, observer: Observer) { - + override fun observe(owner: LifecycleOwner, observer: Observer) { if (hasActiveObservers()) { Log.w(TAG, "Multiple observers registered but only one will be notified of changes.") } // Observe the internal MutableLiveData - super.observe(owner, Observer { t -> + super.observe(owner, { t -> if (pending.compareAndSet(true, false)) { observer.onChanged(t) } diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/detail/DetailActivity.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/detail/DetailActivity.kt index 7ea807b..d23f7c9 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/detail/DetailActivity.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/detail/DetailActivity.kt @@ -1,9 +1,8 @@ package fr.ekito.myweatherapp.view.detail -import android.arch.lifecycle.Observer import android.os.Bundle -import android.support.design.widget.Snackbar -import android.support.v7.app.AppCompatActivity +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.snackbar.Snackbar import fr.ekito.myweatherapp.R import fr.ekito.myweatherapp.domain.entity.DailyForecast import fr.ekito.myweatherapp.domain.entity.getColorFromCode @@ -27,7 +26,7 @@ class DetailActivity : AppCompatActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_detail) - detailViewModel.states.observe(this, Observer { state -> + detailViewModel.states.observe(this, { state -> when (state) { is Failed -> showError(state.error) is DetailViewModel.DetailLoaded -> showDetail(state.weather) @@ -36,7 +35,7 @@ class DetailActivity : AppCompatActivity() { detailViewModel.getDetail() } - fun showError(error: Throwable) { + private fun showError(error: Throwable) { Snackbar.make( weatherItem, getString(R.string.loading_error) + " - $error", diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/detail/DetailViewModel.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/detail/DetailViewModel.kt index b260382..9c9ef1a 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/detail/DetailViewModel.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/detail/DetailViewModel.kt @@ -1,7 +1,7 @@ package fr.ekito.myweatherapp.view.detail -import android.arch.lifecycle.LiveData -import android.arch.lifecycle.MutableLiveData +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import fr.ekito.myweatherapp.domain.entity.DailyForecast import fr.ekito.myweatherapp.domain.repository.DailyForecastRepository import fr.ekito.myweatherapp.util.mvvm.RxViewModel diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashActivity.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashActivity.kt index 569dc5e..9fd7d67 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashActivity.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashActivity.kt @@ -1,11 +1,10 @@ package fr.ekito.myweatherapp.view.splash -import android.arch.lifecycle.Observer import android.os.Bundle -import android.support.design.widget.Snackbar -import android.support.v7.app.AppCompatActivity import android.view.View import android.view.animation.AnimationUtils +import androidx.appcompat.app.AppCompatActivity +import com.google.android.material.snackbar.Snackbar import fr.ekito.myweatherapp.R import fr.ekito.myweatherapp.view.Error import fr.ekito.myweatherapp.view.Pending @@ -29,7 +28,7 @@ class SplashActivity : AppCompatActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_splash) - splashViewModel.events.observe(this, Observer { event -> + splashViewModel.events.observe(this, { event -> when (event) { is Pending -> showIsLoading() is Success -> showIsLoaded() diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashViewModel.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashViewModel.kt index c51ac31..b10845c 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashViewModel.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashViewModel.kt @@ -1,6 +1,6 @@ package fr.ekito.myweatherapp.view.splash -import android.arch.lifecycle.LiveData +import androidx.lifecycle.LiveData import fr.ekito.myweatherapp.domain.repository.DailyForecastRepository import fr.ekito.myweatherapp.util.mvvm.RxViewModel import fr.ekito.myweatherapp.util.mvvm.SingleLiveEvent diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherActivity.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherActivity.kt index f04a492..a721f47 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherActivity.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherActivity.kt @@ -1,11 +1,11 @@ package fr.ekito.myweatherapp.view.weather -import android.arch.lifecycle.Observer import android.os.Bundle -import android.support.design.widget.Snackbar -import android.support.v7.app.AppCompatActivity import android.util.Log import android.view.View +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.Observer +import com.google.android.material.snackbar.Snackbar import fr.ekito.myweatherapp.R import fr.ekito.myweatherapp.view.Failed import kotlinx.android.synthetic.main.activity_result.* @@ -15,6 +15,7 @@ import org.jetbrains.anko.intentFor import org.jetbrains.anko.newTask import org.koin.android.viewmodel.ext.android.viewModel + /** * Weather Result View */ diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherHeaderFragment.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherHeaderFragment.kt index 49a9b2d..05f71a5 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherHeaderFragment.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherHeaderFragment.kt @@ -1,22 +1,22 @@ package fr.ekito.myweatherapp.view.weather import android.app.AlertDialog -import android.arch.lifecycle.Observer +import android.content.Intent import android.os.Bundle -import android.support.design.widget.Snackbar -import android.support.v4.app.Fragment import android.text.InputType import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.EditText +import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import com.google.android.material.snackbar.Snackbar import fr.ekito.myweatherapp.R import fr.ekito.myweatherapp.domain.entity.DailyForecast import fr.ekito.myweatherapp.domain.entity.getColorFromCode import fr.ekito.myweatherapp.view.detail.DetailActivity import fr.ekito.myweatherapp.view.detail.DetailActivity.Companion.INTENT_WEATHER_ID import kotlinx.android.synthetic.main.fragment_result_header.* -import org.jetbrains.anko.startActivity import org.koin.android.viewmodel.ext.android.sharedViewModel class WeatherHeaderFragment : Fragment() { @@ -33,17 +33,17 @@ class WeatherHeaderFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - viewModel.states.observe(this, Observer { state -> + viewModel.states.observe(viewLifecycleOwner, { state -> when (state) { is WeatherViewModel.WeatherListLoaded -> showWeather(state.location, state.first) } }) - viewModel.events.observe(this, Observer { event -> + viewModel.events.observe(viewLifecycleOwner, { event -> when (event) { is WeatherViewModel.ProceedLocation -> showLoadingLocation(event.location) is WeatherViewModel.ProceedLocationError -> showLocationSearchFailed( - event.location, - event.error + event.location, + event.error ) } }) @@ -60,12 +60,12 @@ class WeatherHeaderFragment : Fragment() { weatherTempText.text = weather.temperature.toString() weatherText.text = weather.shortText - val color = context!!.getColorFromCode(weather) + val color = requireContext().getColorFromCode(weather) weatherHeader.background.setTint(color) weatherHeader.setOnClickListener { - activity?.startActivity( - INTENT_WEATHER_ID to weather.id + activity?.startActivity( + Intent(context, DetailActivity::class.java).putExtra(INTENT_WEATHER_ID, weather.id) ) } } diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherListFragment.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherListFragment.kt index 233a52f..527854a 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherListFragment.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherListFragment.kt @@ -1,18 +1,17 @@ package fr.ekito.myweatherapp.view.weather -import android.arch.lifecycle.Observer +import android.content.Intent import android.os.Bundle -import android.support.v4.app.Fragment -import android.support.v7.widget.LinearLayoutManager import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager import fr.ekito.myweatherapp.R import fr.ekito.myweatherapp.view.detail.DetailActivity import fr.ekito.myweatherapp.view.weather.list.WeatherItem import fr.ekito.myweatherapp.view.weather.list.WeatherListAdapter import kotlinx.android.synthetic.main.fragment_result_list.* -import org.jetbrains.anko.startActivity import org.koin.android.viewmodel.ext.android.sharedViewModel class WeatherListFragment : Fragment() { @@ -20,9 +19,9 @@ class WeatherListFragment : Fragment() { private val viewModel: WeatherViewModel by sharedViewModel() override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.fragment_result_list, container, false) } @@ -30,7 +29,7 @@ class WeatherListFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) prepareListView() - viewModel.states.observe(this, Observer { state -> + viewModel.states.observe(viewLifecycleOwner, { state -> when (state) { is WeatherViewModel.WeatherListLoaded -> showWeatherItemList(state.lasts.map { WeatherItem.from(it) @@ -41,17 +40,20 @@ class WeatherListFragment : Fragment() { private fun prepareListView() { weatherList.layoutManager = - LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) + LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) weatherList.adapter = WeatherListAdapter( - activity!!, - emptyList(), - ::onWeatherItemSelected + requireActivity(), + emptyList(), + ::onWeatherItemSelected ) } private fun onWeatherItemSelected(resultItem: WeatherItem) { - activity?.startActivity( - DetailActivity.INTENT_WEATHER_ID to resultItem.id + activity?.startActivity( + Intent(context, DetailActivity::class.java).putExtra( + DetailActivity.INTENT_WEATHER_ID, + resultItem.id + ) ) } diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherViewModel.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherViewModel.kt index 8313308..8f00b69 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherViewModel.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherViewModel.kt @@ -1,7 +1,7 @@ package fr.ekito.myweatherapp.view.weather -import android.arch.lifecycle.LiveData -import android.arch.lifecycle.MutableLiveData +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import fr.ekito.myweatherapp.domain.entity.DailyForecast import fr.ekito.myweatherapp.domain.repository.DailyForecastRepository import fr.ekito.myweatherapp.util.coroutines.SchedulerProvider diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/list/WeatherListAdapter.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/list/WeatherListAdapter.kt index 28ae366..cb3295f 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/list/WeatherListAdapter.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/list/WeatherListAdapter.kt @@ -1,18 +1,18 @@ package fr.ekito.myweatherapp.view.weather.list import android.content.Context -import android.support.v7.widget.RecyclerView import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.LinearLayout import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView import com.joanzapata.iconify.widget.IconTextView import fr.ekito.myweatherapp.R import fr.ekito.myweatherapp.domain.entity.getColorFromCode class WeatherListAdapter( - val context: Context, + private val context: Context, var list: List, private val onDetailSelected: (WeatherItem) -> Unit ) : RecyclerView.Adapter() { diff --git a/examples/android-weather-app/src/main/res/layout/activity_detail.xml b/examples/android-weather-app/src/main/res/layout/activity_detail.xml index 68579d2..90f467f 100644 --- a/examples/android-weather-app/src/main/res/layout/activity_detail.xml +++ b/examples/android-weather-app/src/main/res/layout/activity_detail.xml @@ -1,5 +1,5 @@ - - - - + diff --git a/examples/android-weather-app/src/main/res/layout/fragment_result_header.xml b/examples/android-weather-app/src/main/res/layout/fragment_result_header.xml index e314753..4fd99c1 100644 --- a/examples/android-weather-app/src/main/res/layout/fragment_result_header.xml +++ b/examples/android-weather-app/src/main/res/layout/fragment_result_header.xml @@ -1,5 +1,6 @@ + app:tint="@color/icons_black" /> diff --git a/examples/android-weather-app/src/main/res/layout/fragment_result_list.xml b/examples/android-weather-app/src/main/res/layout/fragment_result_list.xml index 9454c64..3eb4cac 100644 --- a/examples/android-weather-app/src/main/res/layout/fragment_result_list.xml +++ b/examples/android-weather-app/src/main/res/layout/fragment_result_list.xml @@ -6,7 +6,7 @@ android:gravity="center" android:orientation="vertical"> - + tools:context="fr.ekito.myweatherapp.MainActivity" /> diff --git a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/integration/WeatherRepositoryTest.kt b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/integration/WeatherRepositoryTest.kt index 2adbb2d..c8b53fd 100644 --- a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/integration/WeatherRepositoryTest.kt +++ b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/integration/WeatherRepositoryTest.kt @@ -2,8 +2,9 @@ package fr.ekito.myweatherapp.integration import fr.ekito.myweatherapp.di.testWeatherApp import fr.ekito.myweatherapp.domain.repository.DailyForecastRepository -import junit.framework.Assert import org.junit.After +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotSame import org.junit.Before import org.junit.Test import org.koin.core.context.startKoin @@ -13,7 +14,7 @@ import org.koin.test.inject class WeatherRepositoryTest : KoinTest { - val repository by inject() + private val repository by inject() val location = "Paris" @@ -43,8 +44,8 @@ class WeatherRepositoryTest : KoinTest { val l2 = repository.getWeather("Toulouse").blockingGet() val l3 = repository.getWeather().blockingGet() - Assert.assertEquals(l3, l2) - Assert.assertNotSame(l1, l2) + assertEquals(l3, l2) + assertNotSame(l1, l2) } @Test diff --git a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/MockedData.kt b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/MockedData.kt index 6a24478..c9f1a20 100644 --- a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/MockedData.kt +++ b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/MockedData.kt @@ -10,7 +10,7 @@ import fr.ekito.myweatherapp.domain.entity.Wind */ object MockedData { - val location = "Location" + const val location = "Location" val mockList = listOf( DailyForecast( diff --git a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/DetailViewModelMockTest.kt b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/DetailViewModelMockTest.kt index 191af97..e51b796 100644 --- a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/DetailViewModelMockTest.kt +++ b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/DetailViewModelMockTest.kt @@ -1,7 +1,7 @@ package fr.ekito.myweatherapp.mock.mvvm -import android.arch.core.executor.testing.InstantTaskExecutorRule -import android.arch.lifecycle.Observer +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.lifecycle.Observer import fr.ekito.myweatherapp.domain.entity.DailyForecast import fr.ekito.myweatherapp.domain.repository.DailyForecastRepository import fr.ekito.myweatherapp.util.TestSchedulerProvider @@ -24,16 +24,18 @@ import org.mockito.MockitoAnnotations class DetailViewModelMockTest { - lateinit var detailViewModel: DetailViewModel + private lateinit var detailViewModel: DetailViewModel + @Mock lateinit var view: Observer + @Mock lateinit var repository: DailyForecastRepository @get:Rule val rule = InstantTaskExecutorRule() - val id = "ID" + private val id = "ID" @Before fun before() { @@ -65,7 +67,7 @@ class DetailViewModelMockTest { } @Test - fun testGeLasttWeatherFailed() { + fun testGeLastWeatherFailed() { val error = Throwable("Got error") given(repository.getWeatherDetail(id)).willReturn(Single.error(error)) diff --git a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/SplashViewModelMockTest.kt b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/SplashViewModelMockTest.kt index e240c88..53cb684 100644 --- a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/SplashViewModelMockTest.kt +++ b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/SplashViewModelMockTest.kt @@ -1,7 +1,7 @@ package fr.ekito.myweatherapp.mock.mvvm -import android.arch.core.executor.testing.InstantTaskExecutorRule -import android.arch.lifecycle.Observer +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.lifecycle.Observer import fr.ekito.myweatherapp.domain.entity.DailyForecast import fr.ekito.myweatherapp.domain.repository.DailyForecastRepository import fr.ekito.myweatherapp.util.TestSchedulerProvider @@ -23,7 +23,7 @@ import org.mockito.MockitoAnnotations class SplashViewModelMockTest { - lateinit var viewModel: SplashViewModel + private lateinit var viewModel: SplashViewModel @Mock lateinit var view: Observer @@ -64,7 +64,7 @@ class SplashViewModelMockTest { } @Test - fun testGetLasttWeatherFailed() { + fun testGetLastWeatherFailed() { val error = Throwable("Got an error") given(repository.getWeather()).willReturn(Single.error(error)) diff --git a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/WeatherHeaderViewModelMockTest.kt b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/WeatherHeaderViewModelMockTest.kt index d0f35b3..559af90 100644 --- a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/WeatherHeaderViewModelMockTest.kt +++ b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/WeatherHeaderViewModelMockTest.kt @@ -1,7 +1,7 @@ package fr.ekito.myweatherapp.mock.mvvm -import android.arch.core.executor.testing.InstantTaskExecutorRule -import android.arch.lifecycle.Observer +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.lifecycle.Observer import fr.ekito.myweatherapp.domain.repository.DailyForecastRepository import fr.ekito.myweatherapp.mock.MockedData.mockList import fr.ekito.myweatherapp.util.MockitoHelper @@ -25,7 +25,7 @@ import org.mockito.MockitoAnnotations class WeatherHeaderViewModelMockTest { - lateinit var viewModel: WeatherViewModel + private lateinit var viewModel: WeatherViewModel @Mock lateinit var viewStates: Observer diff --git a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/WeatherListViewModelMockTest.kt b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/WeatherListViewModelMockTest.kt index b7feb38..464e33b 100644 --- a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/WeatherListViewModelMockTest.kt +++ b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/WeatherListViewModelMockTest.kt @@ -1,7 +1,7 @@ package fr.ekito.myweatherapp.mock.mvvm -import android.arch.core.executor.testing.InstantTaskExecutorRule -import android.arch.lifecycle.Observer +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.lifecycle.Observer import fr.ekito.myweatherapp.domain.repository.DailyForecastRepository import fr.ekito.myweatherapp.mock.MockedData.mockList import fr.ekito.myweatherapp.util.TestSchedulerProvider @@ -23,9 +23,11 @@ import org.mockito.MockitoAnnotations class WeatherListViewModelMockTest { - lateinit var viewModel: WeatherViewModel + private lateinit var viewModel: WeatherViewModel + @Mock lateinit var view: Observer + @Mock lateinit var repository: DailyForecastRepository diff --git a/gradle.properties b/gradle.properties index 730b81c..0a76a5f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -24,3 +24,7 @@ org.gradle.configureondemand=false # Kotlin kotlin.incremental=true org.gradle.caching=true + +# Enable AndroidX +android.useAndroidX=true +android.enableJetifier=true diff --git a/gradle/versions-android.gradle b/gradle/versions-android.gradle index 0299318..9536b36 100644 --- a/gradle/versions-android.gradle +++ b/gradle/versions-android.gradle @@ -1,13 +1,13 @@ ext { // Sdk and tools - android_min_version = 14 - android_target_version = 28 + android_min_version = 21 + android_target_version = 30 - android_gradle_version = "3.2.1" - android_build_tools_version = '28.0.3' + android_gradle_version = "7.0.0" + android_build_tools_version = '30.0.2' support_lib_version = "28.0.0" androidx_lib_version = "1.0.2" - android_arch_version = '1.1.1' - androidx_arch_version = '2.0.0-rc01' + arch_version = "2.1.0" + lifecycle_version = '2.3.1' } \ No newline at end of file diff --git a/gradle/versions-examples.gradle b/gradle/versions-examples.gradle index 1bf2d3b..c7444cb 100644 --- a/gradle/versions-examples.gradle +++ b/gradle/versions-examples.gradle @@ -1,13 +1,13 @@ ext { // Android Support support_lib_version = "28.0.0" - constraint_layout_version = "1.1.3" - room_version = "1.1.1" + constraint_layout_version = "2.1.0" + room_version = "2.3.0" - leak_canary_version = "1.6.1" + leak_canary_version = "2.7" anko_version='0.10.4' - okhttp_version = '3.8.1' - retrofit_version = '2.2.0' - rxjava_version = '2.1.7' + okhttp_version = '4.9.1' + retrofit_version = '2.9.0' + rxjava_version = '2.2.21' } \ No newline at end of file diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 4d959c4..4009963 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -1,10 +1,10 @@ ext { // Koin - koin_version = '2.0.1' + koin_version = '2.2.3' // Kotlin - kotlin_version = '1.3.21' - coroutines_version = "1.0.0" + kotlin_version = '1.5.21' + coroutines_version = "1.5.1" // Dokka dokka_version = '0.9.16' @@ -19,8 +19,8 @@ ext { // spark_kotlin_version = '1.0.0-alpha' // Test - junit_version = "4.12" - mockito_version = "2.21.0" + junit_version = "4.13.2" + mockito_version = "2.23.4" asciidoctor_version = "1.5.3" asciidoctor_pdf_version = "1.5.0-alpha.15" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0772cac..0f80bbf 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Tue Nov 13 18:16:32 CET 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-all.zip diff --git a/gradlew b/gradlew index 9d82f78..cccdd3d 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,20 +6,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,26 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -85,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -150,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 597e21c..f955316 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -5,17 +5,17 @@ @rem @rem ########################################################################## -@rem Set local modulePath for the variables with windows NT shell +@rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line @@ -75,7 +69,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end -@rem End local modulePath for the variables with windows NT shell +@rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail From 45ce736d161d96b59c689ba9e03b7cac3413597e Mon Sep 17 00:00:00 2001 From: wiryadev Date: Sun, 15 Aug 2021 12:43:36 +0700 Subject: [PATCH 02/18] upgrade `koin` version to 3.1.x --- examples/android-weather-app/build.gradle | 2 +- .../java/fr/ekito/myweatherapp/WeatherDAOTest.kt | 1 - .../main/kotlin/fr/ekito/myweatherapp/di/app_module.kt | 2 +- .../fr/ekito/myweatherapp/di/room_datasource_module.kt | 2 +- .../fr/ekito/myweatherapp/view/detail/DetailActivity.kt | 2 +- .../fr/ekito/myweatherapp/view/splash/SplashActivity.kt | 2 +- .../ekito/myweatherapp/view/weather/WeatherActivity.kt | 9 +++++---- .../myweatherapp/view/weather/WeatherHeaderFragment.kt | 3 +-- .../myweatherapp/view/weather/WeatherListFragment.kt | 2 +- .../test/java/fr/ekito/myweatherapp/ModuleCheckTest.kt | 1 + gradle/versions.gradle | 2 +- 11 files changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/android-weather-app/build.gradle b/examples/android-weather-app/build.gradle index 34ae07a..37f95b0 100644 --- a/examples/android-weather-app/build.gradle +++ b/examples/android-weather-app/build.gradle @@ -60,9 +60,9 @@ dependencies { // Anko implementation "org.jetbrains.anko:anko-commons:$anko_version" + // Koin implementation "io.insert-koin:koin-android:$koin_version" - implementation "io.insert-koin:koin-android-viewmodel:$koin_version" testImplementation "io.insert-koin:koin-test:$koin_version" androidTestImplementation "io.insert-koin:koin-test:$koin_version" diff --git a/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/WeatherDAOTest.kt b/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/WeatherDAOTest.kt index b1bc3e4..7efd077 100644 --- a/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/WeatherDAOTest.kt +++ b/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/WeatherDAOTest.kt @@ -7,7 +7,6 @@ import fr.ekito.myweatherapp.data.room.WeatherDatabase import fr.ekito.myweatherapp.data.room.WeatherEntity import fr.ekito.myweatherapp.domain.ext.getDailyForecasts import fr.ekito.myweatherapp.domain.ext.getLocation -import junit.framework.Assert import org.junit.After import org.junit.Assert.assertEquals import org.junit.Before diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/di/app_module.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/di/app_module.kt index d6d2250..1f38f3f 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/di/app_module.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/di/app_module.kt @@ -7,7 +7,7 @@ import fr.ekito.myweatherapp.util.coroutines.SchedulerProvider import fr.ekito.myweatherapp.view.detail.DetailViewModel import fr.ekito.myweatherapp.view.splash.SplashViewModel import fr.ekito.myweatherapp.view.weather.WeatherViewModel -import org.koin.android.viewmodel.dsl.viewModel +import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.dsl.module /** diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/di/room_datasource_module.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/di/room_datasource_module.kt index 4515973..aa93c7f 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/di/room_datasource_module.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/di/room_datasource_module.kt @@ -11,7 +11,7 @@ import org.koin.dsl.module val roomDataSourceModule = module { // Weather Room Data Repository - single(override = true) { + single { DailyForecastRepositoryRoomImpl( get(), get() diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/detail/DetailActivity.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/detail/DetailActivity.kt index d23f7c9..01697ca 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/detail/DetailActivity.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/detail/DetailActivity.kt @@ -9,7 +9,7 @@ import fr.ekito.myweatherapp.domain.entity.getColorFromCode import fr.ekito.myweatherapp.util.android.argument import fr.ekito.myweatherapp.view.Failed import kotlinx.android.synthetic.main.activity_detail.* -import org.koin.android.viewmodel.ext.android.viewModel +import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.core.parameter.parametersOf /** diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashActivity.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashActivity.kt index 9fd7d67..202d10c 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashActivity.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashActivity.kt @@ -15,7 +15,7 @@ import org.jetbrains.anko.clearTask import org.jetbrains.anko.clearTop import org.jetbrains.anko.intentFor import org.jetbrains.anko.newTask -import org.koin.android.viewmodel.ext.android.viewModel +import org.koin.androidx.viewmodel.ext.android.viewModel /** * Search Weather View diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherActivity.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherActivity.kt index a721f47..b229876 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherActivity.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherActivity.kt @@ -4,7 +4,6 @@ import android.os.Bundle import android.util.Log import android.view.View import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.Observer import com.google.android.material.snackbar.Snackbar import fr.ekito.myweatherapp.R import fr.ekito.myweatherapp.view.Failed @@ -13,7 +12,7 @@ import org.jetbrains.anko.clearTask import org.jetbrains.anko.clearTop import org.jetbrains.anko.intentFor import org.jetbrains.anko.newTask -import org.koin.android.viewmodel.ext.android.viewModel +import org.koin.androidx.viewmodel.ext.android.viewModel /** @@ -21,7 +20,9 @@ import org.koin.android.viewmodel.ext.android.viewModel */ class WeatherActivity : AppCompatActivity() { - private val TAG = this::class.java.simpleName + companion object { + private val TAG = this::class.java.simpleName + } private val viewModel: WeatherViewModel by viewModel() @@ -41,7 +42,7 @@ class WeatherActivity : AppCompatActivity() { .replace(R.id.weather_list, resultListFragment) .commit() - viewModel.states.observe(this, Observer { state -> + viewModel.states.observe(this, { state -> when (state) { is Failed -> showError(state.error) } diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherHeaderFragment.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherHeaderFragment.kt index 05f71a5..b30bc38 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherHeaderFragment.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherHeaderFragment.kt @@ -9,7 +9,6 @@ import android.view.View import android.view.ViewGroup import android.widget.EditText import androidx.fragment.app.Fragment -import androidx.lifecycle.Observer import com.google.android.material.snackbar.Snackbar import fr.ekito.myweatherapp.R import fr.ekito.myweatherapp.domain.entity.DailyForecast @@ -17,7 +16,7 @@ import fr.ekito.myweatherapp.domain.entity.getColorFromCode import fr.ekito.myweatherapp.view.detail.DetailActivity import fr.ekito.myweatherapp.view.detail.DetailActivity.Companion.INTENT_WEATHER_ID import kotlinx.android.synthetic.main.fragment_result_header.* -import org.koin.android.viewmodel.ext.android.sharedViewModel +import org.koin.androidx.viewmodel.ext.android.sharedViewModel class WeatherHeaderFragment : Fragment() { diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherListFragment.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherListFragment.kt index 527854a..4291975 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherListFragment.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherListFragment.kt @@ -12,7 +12,7 @@ import fr.ekito.myweatherapp.view.detail.DetailActivity import fr.ekito.myweatherapp.view.weather.list.WeatherItem import fr.ekito.myweatherapp.view.weather.list.WeatherListAdapter import kotlinx.android.synthetic.main.fragment_result_list.* -import org.koin.android.viewmodel.ext.android.sharedViewModel +import org.koin.androidx.viewmodel.ext.android.sharedViewModel class WeatherListFragment : Fragment() { diff --git a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/ModuleCheckTest.kt b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/ModuleCheckTest.kt index c4bd8ce..00761b6 100644 --- a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/ModuleCheckTest.kt +++ b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/ModuleCheckTest.kt @@ -11,6 +11,7 @@ import org.koin.android.ext.koin.androidContext import org.koin.core.logger.Level import org.koin.core.parameter.parametersOf import org.koin.dsl.koinApplication +import org.koin.fileProperties import org.koin.test.KoinTest import org.koin.test.check.checkModules import org.mockito.Mockito.mock diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 4009963..8f4da5e 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -1,6 +1,6 @@ ext { // Koin - koin_version = '2.2.3' + koin_version = '3.1.2' // Kotlin kotlin_version = '1.5.21' From 2db856589455b44485106ab84d8197a7eea357df Mon Sep 17 00:00:00 2001 From: wiryadev Date: Sun, 15 Aug 2021 12:44:44 +0700 Subject: [PATCH 03/18] fix indentation --- .../view/weather/WeatherHeaderFragment.kt | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherHeaderFragment.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherHeaderFragment.kt index b30bc38..89a45b0 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherHeaderFragment.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherHeaderFragment.kt @@ -23,9 +23,9 @@ class WeatherHeaderFragment : Fragment() { private val viewModel: WeatherViewModel by sharedViewModel() override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? ): View { return inflater.inflate(R.layout.fragment_result_header, container, false) as ViewGroup } @@ -90,18 +90,18 @@ class WeatherHeaderFragment : Fragment() { private fun showLoadingLocation(location: String) { Snackbar.make( - weatherHeader, - getString(R.string.loading_location) + " $location ...", - Snackbar.LENGTH_LONG + weatherHeader, + getString(R.string.loading_location) + " $location ...", + Snackbar.LENGTH_LONG ) - .show() + .show() } private fun showLocationSearchFailed(location: String, error: Throwable) { Snackbar.make(weatherHeader, getString(R.string.loading_error), Snackbar.LENGTH_LONG) - .setAction(R.string.retry) { - viewModel.loadNewLocation(location) - } - .show() + .setAction(R.string.retry) { + viewModel.loadNewLocation(location) + } + .show() } } \ No newline at end of file From 83f2b1a9e10c11c5f6090d3784ddda5002eaca23 Mon Sep 17 00:00:00 2001 From: wiryadev Date: Sun, 15 Aug 2021 13:56:28 +0700 Subject: [PATCH 04/18] remove deprecated method --- .../java/fr/ekito/myweatherapp/room_test_modules.kt | 4 ++-- .../src/test/java/fr/ekito/myweatherapp/di/test_modules.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/room_test_modules.kt b/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/room_test_modules.kt index d48847e..d82609d 100644 --- a/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/room_test_modules.kt +++ b/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/room_test_modules.kt @@ -4,8 +4,8 @@ import androidx.room.Room import fr.ekito.myweatherapp.data.room.WeatherDatabase import org.koin.dsl.module -// Room In memroy database -val roomTestModule = module(override = true) { +// Room In memory database +val roomTestModule = module { single { Room.inMemoryDatabaseBuilder(get(), WeatherDatabase::class.java) .allowMainThreadQueries() diff --git a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/di/test_modules.kt b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/di/test_modules.kt index 6ccf4f8..b2308fb 100644 --- a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/di/test_modules.kt +++ b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/di/test_modules.kt @@ -12,7 +12,7 @@ import org.koin.dsl.module /** * Local java json repository */ -val localJavaDatasourceModule = module(override = true) { +val localJavaDatasourceModule = module { single { JavaReader() } single { FileDataSource(get(), false) } } @@ -20,7 +20,7 @@ val localJavaDatasourceModule = module(override = true) { /** * Test Rx */ -val testRxModule = module(override = true) { +val testRxModule = module { // provided components single { TestSchedulerProvider() } } From 69e5e3d64d97cde00a0da8667c05a6f56e08b881 Mon Sep 17 00:00:00 2001 From: wiryadev Date: Sun, 15 Aug 2021 14:33:57 +0700 Subject: [PATCH 05/18] enable viewBinding in activity --- examples/android-weather-app/build.gradle | 3 ++ .../view/detail/DetailActivity.kt | 35 +++++++++++-------- .../view/splash/SplashActivity.kt | 19 ++++++---- .../view/weather/WeatherActivity.kt | 32 +++++++++-------- 4 files changed, 53 insertions(+), 36 deletions(-) diff --git a/examples/android-weather-app/build.gradle b/examples/android-weather-app/build.gradle index 37f95b0..8f271e7 100644 --- a/examples/android-weather-app/build.gradle +++ b/examples/android-weather-app/build.gradle @@ -45,6 +45,9 @@ android { androidTest.assets.srcDirs += files("$projectDir/schemas".toString()) } + buildFeatures { + viewBinding true + } } dependencies { diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/detail/DetailActivity.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/detail/DetailActivity.kt index 01697ca..2c2474f 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/detail/DetailActivity.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/detail/DetailActivity.kt @@ -4,11 +4,11 @@ import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.google.android.material.snackbar.Snackbar import fr.ekito.myweatherapp.R +import fr.ekito.myweatherapp.databinding.ActivityDetailBinding import fr.ekito.myweatherapp.domain.entity.DailyForecast import fr.ekito.myweatherapp.domain.entity.getColorFromCode import fr.ekito.myweatherapp.util.android.argument import fr.ekito.myweatherapp.view.Failed -import kotlinx.android.synthetic.main.activity_detail.* import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.core.parameter.parametersOf @@ -17,14 +17,17 @@ import org.koin.core.parameter.parametersOf */ class DetailActivity : AppCompatActivity() { + private lateinit var binding: ActivityDetailBinding + // Get all needed data private val detailId by argument(INTENT_WEATHER_ID) - val detailViewModel: DetailViewModel by viewModel { parametersOf(detailId) } + private val detailViewModel: DetailViewModel by viewModel { parametersOf(detailId) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_detail) + binding = ActivityDetailBinding.inflate(layoutInflater) + setContentView(binding.root) detailViewModel.states.observe(this, { state -> when (state) { @@ -37,23 +40,25 @@ class DetailActivity : AppCompatActivity() { private fun showError(error: Throwable) { Snackbar.make( - weatherItem, + binding.weatherItem, getString(R.string.loading_error) + " - $error", Snackbar.LENGTH_LONG ).show() } - fun showDetail(weather: DailyForecast) { - weatherIcon.text = weather.icon - weatherDay.text = weather.day - weatherText.text = weather.fullText - weatherWindText.text = weather.wind.toString() - weatherTempText.text = weather.temperature.toString() - weatherHumidityText.text = weather.humidity.toString() - weatherItem.background.setTint(getColorFromCode(weather)) - // Set back on background click - weatherItem.setOnClickListener { - onBackPressed() + private fun showDetail(weather: DailyForecast) { + with(binding) { + weatherIcon.text = weather.icon + weatherDay.text = weather.day + weatherText.text = weather.fullText + weatherWindText.text = weather.wind.toString() + weatherTempText.text = weather.temperature.toString() + weatherHumidityText.text = weather.humidity.toString() + weatherItem.background.setTint(getColorFromCode(weather)) + // Set back on background click + weatherItem.setOnClickListener { + onBackPressed() + } } } diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashActivity.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashActivity.kt index 202d10c..1beedd1 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashActivity.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashActivity.kt @@ -6,11 +6,11 @@ import android.view.animation.AnimationUtils import androidx.appcompat.app.AppCompatActivity import com.google.android.material.snackbar.Snackbar import fr.ekito.myweatherapp.R +import fr.ekito.myweatherapp.databinding.ActivitySplashBinding import fr.ekito.myweatherapp.view.Error import fr.ekito.myweatherapp.view.Pending import fr.ekito.myweatherapp.view.Success import fr.ekito.myweatherapp.view.weather.WeatherActivity -import kotlinx.android.synthetic.main.activity_splash.* import org.jetbrains.anko.clearTask import org.jetbrains.anko.clearTop import org.jetbrains.anko.intentFor @@ -22,11 +22,14 @@ import org.koin.androidx.viewmodel.ext.android.viewModel */ class SplashActivity : AppCompatActivity() { + private lateinit var binding: ActivitySplashBinding + private val splashViewModel: SplashViewModel by viewModel() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_splash) + binding = ActivitySplashBinding.inflate(layoutInflater) + setContentView(binding.root) splashViewModel.events.observe(this, { event -> when (event) { @@ -40,8 +43,8 @@ class SplashActivity : AppCompatActivity() { private fun showIsLoading() { val animation = - AnimationUtils.loadAnimation(applicationContext, R.anim.infinite_blinking_animation) - splashIcon.startAnimation(animation) + AnimationUtils.loadAnimation(applicationContext, R.anim.infinite_blinking_animation) + binding.splashIcon.startAnimation(animation) } private fun showIsLoaded() { @@ -49,12 +52,14 @@ class SplashActivity : AppCompatActivity() { } private fun showError(error: Throwable) { - splashIcon.visibility = View.GONE - splashIconFail.visibility = View.VISIBLE - Snackbar.make(splash, "SplashActivity got error : $error", Snackbar.LENGTH_INDEFINITE) + with(binding) { + splashIcon.visibility = View.GONE + splashIconFail.visibility = View.VISIBLE + Snackbar.make(splash, "SplashActivity got error : $error", Snackbar.LENGTH_INDEFINITE) .setAction(R.string.retry) { splashViewModel.getLastWeather() } .show() + } } } diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherActivity.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherActivity.kt index b229876..d176cda 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherActivity.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherActivity.kt @@ -6,15 +6,14 @@ import android.view.View import androidx.appcompat.app.AppCompatActivity import com.google.android.material.snackbar.Snackbar import fr.ekito.myweatherapp.R +import fr.ekito.myweatherapp.databinding.ActivityResultBinding import fr.ekito.myweatherapp.view.Failed -import kotlinx.android.synthetic.main.activity_result.* import org.jetbrains.anko.clearTask import org.jetbrains.anko.clearTop import org.jetbrains.anko.intentFor import org.jetbrains.anko.newTask import org.koin.androidx.viewmodel.ext.android.viewModel - /** * Weather Result View */ @@ -24,23 +23,26 @@ class WeatherActivity : AppCompatActivity() { private val TAG = this::class.java.simpleName } + private lateinit var binding: ActivityResultBinding + private val viewModel: WeatherViewModel by viewModel() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_result) + binding = ActivityResultBinding.inflate(layoutInflater) + setContentView(binding.root) val weatherTitleFragment = WeatherHeaderFragment() val resultListFragment = WeatherListFragment() supportFragmentManager - .beginTransaction() - .replace(R.id.weather_title, weatherTitleFragment) - .commit() + .beginTransaction() + .replace(R.id.weather_title, weatherTitleFragment) + .commit() supportFragmentManager - .beginTransaction() - .replace(R.id.weather_list, resultListFragment) - .commit() + .beginTransaction() + .replace(R.id.weather_list, resultListFragment) + .commit() viewModel.states.observe(this, { state -> when (state) { @@ -53,16 +55,18 @@ class WeatherActivity : AppCompatActivity() { private fun showError(error: Throwable) { Log.e(TAG, "error $error while displaying weather") - weather_views.visibility = View.GONE - weather_error.visibility = View.VISIBLE - Snackbar.make( - weather_result, + with(binding) { + weatherViews.visibility = View.GONE + weatherError.visibility = View.VISIBLE + Snackbar.make( + weatherResult, "WeatherActivity got error : $error", Snackbar.LENGTH_INDEFINITE - ) + ) .setAction(R.string.retry) { startActivity(intentFor().clearTop().clearTask().newTask()) } .show() + } } } From 65cca087f91084f8cc3e6e88eeeee94419073da7 Mon Sep 17 00:00:00 2001 From: wiryadev Date: Sun, 15 Aug 2021 14:37:03 +0700 Subject: [PATCH 06/18] enable viewBinding in `WeatherHeaderFragment` --- .../view/weather/WeatherHeaderFragment.kt | 50 ++++++++++++------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherHeaderFragment.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherHeaderFragment.kt index 89a45b0..19fa288 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherHeaderFragment.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherHeaderFragment.kt @@ -11,15 +11,18 @@ import android.widget.EditText import androidx.fragment.app.Fragment import com.google.android.material.snackbar.Snackbar import fr.ekito.myweatherapp.R +import fr.ekito.myweatherapp.databinding.FragmentResultHeaderBinding import fr.ekito.myweatherapp.domain.entity.DailyForecast import fr.ekito.myweatherapp.domain.entity.getColorFromCode import fr.ekito.myweatherapp.view.detail.DetailActivity import fr.ekito.myweatherapp.view.detail.DetailActivity.Companion.INTENT_WEATHER_ID -import kotlinx.android.synthetic.main.fragment_result_header.* import org.koin.androidx.viewmodel.ext.android.sharedViewModel class WeatherHeaderFragment : Fragment() { + private var _binding: FragmentResultHeaderBinding? = null + private val binding get() = _binding!! + private val viewModel: WeatherViewModel by sharedViewModel() override fun onCreateView( @@ -27,7 +30,8 @@ class WeatherHeaderFragment : Fragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View { - return inflater.inflate(R.layout.fragment_result_header, container, false) as ViewGroup + _binding = FragmentResultHeaderBinding.inflate(inflater, container, false) + return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -48,24 +52,34 @@ class WeatherHeaderFragment : Fragment() { }) } + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + private fun showWeather(location: String, weather: DailyForecast) { - weatherCity.text = location - weatherCityCard.setOnClickListener { - promptLocationDialog() - } + with(binding) { + weatherCity.text = location + weatherCityCard.setOnClickListener { + promptLocationDialog() + } - weatherIcon.text = weather.icon - weatherDay.text = weather.day - weatherTempText.text = weather.temperature.toString() - weatherText.text = weather.shortText + weatherIcon.text = weather.icon + weatherDay.text = weather.day + weatherTempText.text = weather.temperature.toString() + weatherText.text = weather.shortText - val color = requireContext().getColorFromCode(weather) - weatherHeader.background.setTint(color) + val color = requireContext().getColorFromCode(weather) + weatherHeader.background.setTint(color) - weatherHeader.setOnClickListener { - activity?.startActivity( - Intent(context, DetailActivity::class.java).putExtra(INTENT_WEATHER_ID, weather.id) - ) + weatherHeader.setOnClickListener { + activity?.startActivity( + Intent(context, DetailActivity::class.java).putExtra( + INTENT_WEATHER_ID, + weather.id + ) + ) + } } } @@ -90,7 +104,7 @@ class WeatherHeaderFragment : Fragment() { private fun showLoadingLocation(location: String) { Snackbar.make( - weatherHeader, + binding.weatherHeader, getString(R.string.loading_location) + " $location ...", Snackbar.LENGTH_LONG ) @@ -98,7 +112,7 @@ class WeatherHeaderFragment : Fragment() { } private fun showLocationSearchFailed(location: String, error: Throwable) { - Snackbar.make(weatherHeader, getString(R.string.loading_error), Snackbar.LENGTH_LONG) + Snackbar.make(binding.weatherHeader, getString(R.string.loading_error), Snackbar.LENGTH_LONG) .setAction(R.string.retry) { viewModel.loadNewLocation(location) } From 622a5e6d9fa4316f37a004afe8b8e4ff91741297 Mon Sep 17 00:00:00 2001 From: wiryadev Date: Sun, 15 Aug 2021 14:40:34 +0700 Subject: [PATCH 07/18] enable viewBinding in `WeatherListFragment` --- .../view/weather/WeatherListFragment.kt | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherListFragment.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherListFragment.kt index 4291975..419c958 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherListFragment.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherListFragment.kt @@ -7,23 +7,26 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager -import fr.ekito.myweatherapp.R +import fr.ekito.myweatherapp.databinding.FragmentResultListBinding import fr.ekito.myweatherapp.view.detail.DetailActivity import fr.ekito.myweatherapp.view.weather.list.WeatherItem import fr.ekito.myweatherapp.view.weather.list.WeatherListAdapter -import kotlinx.android.synthetic.main.fragment_result_list.* import org.koin.androidx.viewmodel.ext.android.sharedViewModel class WeatherListFragment : Fragment() { + private var _binding: FragmentResultListBinding? = null + private val binding get() = _binding!! + private val viewModel: WeatherViewModel by sharedViewModel() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { - return inflater.inflate(R.layout.fragment_result_list, container, false) + ): View { + _binding = FragmentResultListBinding.inflate(inflater, container, false) + return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -38,14 +41,21 @@ class WeatherListFragment : Fragment() { }) } + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + private fun prepareListView() { - weatherList.layoutManager = - LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) - weatherList.adapter = WeatherListAdapter( - requireActivity(), - emptyList(), - ::onWeatherItemSelected - ) + with(binding) { + weatherList.layoutManager = + LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) + weatherList.adapter = WeatherListAdapter( + requireActivity(), + emptyList(), + ::onWeatherItemSelected + ) + } } private fun onWeatherItemSelected(resultItem: WeatherItem) { @@ -58,7 +68,7 @@ class WeatherListFragment : Fragment() { } private fun showWeatherItemList(newList: List) { - val adapter: WeatherListAdapter = weatherList.adapter as WeatherListAdapter + val adapter: WeatherListAdapter = binding.weatherList.adapter as WeatherListAdapter adapter.list = newList adapter.notifyDataSetChanged() } From 2d183b3e4a65f8fdb1ec801b3d30fa782fec9e87 Mon Sep 17 00:00:00 2001 From: wiryadev Date: Sun, 15 Aug 2021 14:50:19 +0700 Subject: [PATCH 08/18] enable viewBinding in `WeatherListAdapter` and remove `KAE` --- examples/android-weather-app/build.gradle | 1 - .../view/weather/list/WeatherListAdapter.kt | 32 ++++++++----------- .../src/main/res/layout/item_weather.xml | 6 ++-- .../src/main/res/values/strings.xml | 2 ++ 4 files changed, 19 insertions(+), 22 deletions(-) diff --git a/examples/android-weather-app/build.gradle b/examples/android-weather-app/build.gradle index 8f271e7..84d1da0 100644 --- a/examples/android-weather-app/build.gradle +++ b/examples/android-weather-app/build.gradle @@ -2,7 +2,6 @@ plugins { id 'com.android.application' id 'kotlin-android' id 'kotlin-kapt' - id 'kotlin-android-extensions' } apply from: '../../gradle/versions-examples.gradle' diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/list/WeatherListAdapter.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/list/WeatherListAdapter.kt index cb3295f..409fe51 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/list/WeatherListAdapter.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/list/WeatherListAdapter.kt @@ -2,13 +2,9 @@ package fr.ekito.myweatherapp.view.weather.list import android.content.Context import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup -import android.widget.LinearLayout -import android.widget.TextView import androidx.recyclerview.widget.RecyclerView -import com.joanzapata.iconify.widget.IconTextView -import fr.ekito.myweatherapp.R +import fr.ekito.myweatherapp.databinding.ItemWeatherBinding import fr.ekito.myweatherapp.domain.entity.getColorFromCode class WeatherListAdapter( @@ -18,8 +14,8 @@ class WeatherListAdapter( ) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WeatherResultHolder { - val view = LayoutInflater.from(parent.context).inflate(R.layout.item_weather, parent, false) - return WeatherResultHolder(view) + val binding = ItemWeatherBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return WeatherResultHolder(binding) } override fun onBindViewHolder(holder: WeatherResultHolder, position: Int) { @@ -28,22 +24,22 @@ class WeatherListAdapter( override fun getItemCount() = list.size - inner class WeatherResultHolder(item: View) : RecyclerView.ViewHolder(item) { - private val weatherItemLayout = item.findViewById(R.id.weatherItemLayout) - private val weatherItemDay = item.findViewById(R.id.weatheItemrDay) - private val weatherItemIcon = item.findViewById(R.id.weatherItemIcon) - + inner class WeatherResultHolder( + private val binding: ItemWeatherBinding + ) : RecyclerView.ViewHolder(binding.root) { fun display( dailyForecastModel: WeatherItem, context: Context, onClick: (WeatherItem) -> Unit ) { - weatherItemLayout.setOnClickListener { onClick(dailyForecastModel) } - weatherItemDay.text = dailyForecastModel.day - weatherItemIcon.text = dailyForecastModel.icon - val color = context.getColorFromCode(dailyForecastModel) - weatherItemDay.setTextColor(color) - weatherItemIcon.setTextColor(color) + with(binding) { + weatherItemLayout.setOnClickListener { onClick(dailyForecastModel) } + weatherItemDay.text = dailyForecastModel.day + weatherItemIcon.text = dailyForecastModel.icon + val color = context.getColorFromCode(dailyForecastModel) + weatherItemDay.setTextColor(color) + weatherItemIcon.setTextColor(color) + } } } diff --git a/examples/android-weather-app/src/main/res/layout/item_weather.xml b/examples/android-weather-app/src/main/res/layout/item_weather.xml index 0e6e160..4a536ed 100644 --- a/examples/android-weather-app/src/main/res/layout/item_weather.xml +++ b/examples/android-weather-app/src/main/res/layout/item_weather.xml @@ -28,18 +28,18 @@ android:layout_height="wrap_content" android:layout_margin="8dp" android:gravity="center" - android:text="Icon" + android:text="@string/icon" android:textColor="@color/icons_black" android:textSize="50sp" /> diff --git a/examples/android-weather-app/src/main/res/values/strings.xml b/examples/android-weather-app/src/main/res/values/strings.xml index fc84f4a..8e45bf2 100644 --- a/examples/android-weather-app/src/main/res/values/strings.xml +++ b/examples/android-weather-app/src/main/res/values/strings.xml @@ -7,4 +7,6 @@ CANCEL Retry Loading location + Icon + Day From 89e27d2193e6903200d0e120c019ccd57ea68366 Mon Sep 17 00:00:00 2001 From: wiryadev Date: Sun, 15 Aug 2021 15:00:11 +0700 Subject: [PATCH 09/18] remove Anko --- examples/android-weather-app/build.gradle | 3 --- .../myweatherapp/view/splash/SplashActivity.kt | 13 ++++++++----- .../myweatherapp/view/weather/WeatherActivity.kt | 13 ++++++++----- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/examples/android-weather-app/build.gradle b/examples/android-weather-app/build.gradle index 84d1da0..7983f48 100644 --- a/examples/android-weather-app/build.gradle +++ b/examples/android-weather-app/build.gradle @@ -60,9 +60,6 @@ dependencies { androidTestImplementation 'androidx.test:runner:1.4.0' androidTestUtil 'androidx.test:orchestrator:1.4.0' - // Anko - implementation "org.jetbrains.anko:anko-commons:$anko_version" - // Koin implementation "io.insert-koin:koin-android:$koin_version" testImplementation "io.insert-koin:koin-test:$koin_version" diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashActivity.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashActivity.kt index 1beedd1..58fc281 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashActivity.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashActivity.kt @@ -1,5 +1,6 @@ package fr.ekito.myweatherapp.view.splash +import android.content.Intent import android.os.Bundle import android.view.View import android.view.animation.AnimationUtils @@ -11,10 +12,6 @@ import fr.ekito.myweatherapp.view.Error import fr.ekito.myweatherapp.view.Pending import fr.ekito.myweatherapp.view.Success import fr.ekito.myweatherapp.view.weather.WeatherActivity -import org.jetbrains.anko.clearTask -import org.jetbrains.anko.clearTop -import org.jetbrains.anko.intentFor -import org.jetbrains.anko.newTask import org.koin.androidx.viewmodel.ext.android.viewModel /** @@ -48,7 +45,13 @@ class SplashActivity : AppCompatActivity() { } private fun showIsLoaded() { - startActivity(intentFor().clearTop().clearTask().newTask()) + startActivity( + Intent(this, WeatherActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + } + ) } private fun showError(error: Throwable) { diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherActivity.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherActivity.kt index d176cda..819e13b 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherActivity.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/weather/WeatherActivity.kt @@ -1,5 +1,6 @@ package fr.ekito.myweatherapp.view.weather +import android.content.Intent import android.os.Bundle import android.util.Log import android.view.View @@ -8,10 +9,6 @@ import com.google.android.material.snackbar.Snackbar import fr.ekito.myweatherapp.R import fr.ekito.myweatherapp.databinding.ActivityResultBinding import fr.ekito.myweatherapp.view.Failed -import org.jetbrains.anko.clearTask -import org.jetbrains.anko.clearTop -import org.jetbrains.anko.intentFor -import org.jetbrains.anko.newTask import org.koin.androidx.viewmodel.ext.android.viewModel /** @@ -64,7 +61,13 @@ class WeatherActivity : AppCompatActivity() { Snackbar.LENGTH_INDEFINITE ) .setAction(R.string.retry) { - startActivity(intentFor().clearTop().clearTask().newTask()) + startActivity( + Intent(this@WeatherActivity, WeatherActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + } + ) } .show() } From 8780503e84bf68c289ed6f8569e4c5c0ca51928e Mon Sep 17 00:00:00 2001 From: wiryadev Date: Sun, 15 Aug 2021 15:12:37 +0700 Subject: [PATCH 10/18] minor a11y improvement --- .../src/main/res/layout/activity_detail.xml | 12 ++++++------ .../main/res/layout/fragment_result_header.xml | 17 +++++++++-------- .../src/main/res/values/strings.xml | 5 +++++ 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/examples/android-weather-app/src/main/res/layout/activity_detail.xml b/examples/android-weather-app/src/main/res/layout/activity_detail.xml index 90f467f..a5b30cf 100644 --- a/examples/android-weather-app/src/main/res/layout/activity_detail.xml +++ b/examples/android-weather-app/src/main/res/layout/activity_detail.xml @@ -18,7 +18,7 @@ android:layout_marginStart="24dp" android:layout_marginTop="32dp" android:gravity="center" - android:text="Day" + android:text="@string/day" android:textColor="@color/t_white" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -33,7 +33,7 @@ android:layout_marginStart="8dp" android:layout_marginTop="16dp" android:gravity="center" - android:text="Icon" + android:text="@string/icon" android:textColor="@color/t_white" android:textSize="104sp" app:layout_constraintBottom_toBottomOf="parent" @@ -53,7 +53,7 @@ android:layout_marginTop="24dp" android:gravity="center" android:maxLines="3" - android:text="Complete Text" + android:text="@string/complete_text" android:textColor="@color/t_white" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" @@ -85,7 +85,7 @@ android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:gravity="center|start" - android:text="Wind" + android:text="@string/wind" android:textColor="@color/t_white" app:layout_constraintBottom_toBottomOf="@+id/weatherWind" app:layout_constraintEnd_toEndOf="@+id/weatherText" @@ -115,7 +115,7 @@ android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:gravity="center|start" - android:text="Temp" + android:text="@string/temp" android:textColor="@color/t_white" app:layout_constraintBottom_toBottomOf="@+id/weatherTemp" app:layout_constraintEnd_toEndOf="@+id/weatherText" @@ -145,7 +145,7 @@ android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:gravity="center|start" - android:text="Humidity" + android:text="@string/humidity" android:textColor="@color/t_white" app:layout_constraintBottom_toBottomOf="@+id/weatherHumidity" app:layout_constraintEnd_toEndOf="@+id/weatherText" diff --git a/examples/android-weather-app/src/main/res/layout/fragment_result_header.xml b/examples/android-weather-app/src/main/res/layout/fragment_result_header.xml index 4fd99c1..a927739 100644 --- a/examples/android-weather-app/src/main/res/layout/fragment_result_header.xml +++ b/examples/android-weather-app/src/main/res/layout/fragment_result_header.xml @@ -26,7 +26,7 @@ android:layout_margin="8dp" android:layout_weight="1" android:gravity="center" - android:text="City" + android:text="@string/city" android:textColor="@color/icons_black" /> + app:tint="@color/icons_black" + android:contentDescription="@string/city" /> @@ -56,7 +57,7 @@ android:layout_height="wrap_content" android:layout_margin="24dp" android:gravity="center" - android:text="Day" + android:text="@string/day" android:textSize="21sp" android:textColor="@color/t_white" /> @@ -66,7 +67,7 @@ android:layout_height="wrap_content" android:layout_margin="8dp" android:gravity="center" - android:text="Icon" + android:text="@string/icon" android:textColor="@color/t_white" android:textSize="92sp" /> @@ -77,7 +78,7 @@ android:layout_height="wrap_content" android:layout_margin="16dp" android:gravity="center" - android:text="Complete Text" + android:text="@string/complete_text" android:textColor="@color/t_white" /> @@ -102,8 +103,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="8dp" - android:gravity="center|left" - android:text="Day" + android:gravity="center|start" + android:text="@string/day" android:textColor="@color/t_white" /> diff --git a/examples/android-weather-app/src/main/res/values/strings.xml b/examples/android-weather-app/src/main/res/values/strings.xml index 8e45bf2..d248f88 100644 --- a/examples/android-weather-app/src/main/res/values/strings.xml +++ b/examples/android-weather-app/src/main/res/values/strings.xml @@ -9,4 +9,9 @@ Loading location Icon Day + Complete Text + City + Wind + Temp + Humidity From 392758be93c36ab998fe6d3a50cc10af1a10fe20 Mon Sep 17 00:00:00 2001 From: wiryadev Date: Sun, 15 Aug 2021 15:13:15 +0700 Subject: [PATCH 11/18] replace deprecated method and change visibility modifier --- .../fr/ekito/myweatherapp/data/local/FileDataSource.kt | 5 +++-- .../fr/ekito/myweatherapp/view/splash/SplashViewModel.kt | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/local/FileDataSource.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/local/FileDataSource.kt index 6873778..39aa1c7 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/local/FileDataSource.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/local/FileDataSource.kt @@ -4,12 +4,13 @@ import fr.ekito.myweatherapp.data.WeatherDataSource import fr.ekito.myweatherapp.data.json.Geocode import fr.ekito.myweatherapp.data.json.Weather import io.reactivex.Single +import java.util.Locale import java.util.concurrent.TimeUnit /** * Read json files and render weather date */ -class FileDataSource(val jsonReader: JsonReader, val delayed: Boolean) : +class FileDataSource(private val jsonReader: JsonReader, private val delayed: Boolean) : WeatherDataSource { private val cities by lazy { jsonReader.getAllLocations() } @@ -23,7 +24,7 @@ class FileDataSource(val jsonReader: JsonReader, val delayed: Boolean) : override fun geocode(address: String): Single { val single = Single.create { s -> - val addressToLC = address.toLowerCase() + val addressToLC = address.lowercase(Locale.getDefault()) val geocode = if (isKnownCity(addressToLC)) { jsonReader.getGeocode(addressToLC) } else { diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashViewModel.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashViewModel.kt index b10845c..e2555f7 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashViewModel.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/view/splash/SplashViewModel.kt @@ -24,7 +24,7 @@ class SplashViewModel( _events.value = Pending launch { dailyForecastRepository.getWeather().with(schedulerProvider) - .toCompletable() + .ignoreElement() .subscribe( { _events.value = Success }, { error -> _events.value = Error(error) }) From e918cbc108098e7d1c9cac070e3aa35aeec1ec3a Mon Sep 17 00:00:00 2001 From: wiryadev Date: Sun, 15 Aug 2021 15:39:00 +0700 Subject: [PATCH 12/18] migrate to Rx3 --- examples/android-weather-app/build.gradle | 8 ++++---- .../java/fr/ekito/myweatherapp/WeatherDAOTest.kt | 2 +- .../fr/ekito/myweatherapp/data/WeatherDataSource.kt | 2 +- .../ekito/myweatherapp/data/local/FileDataSource.kt | 2 +- .../fr/ekito/myweatherapp/data/room/WeatherDAO.kt | 2 +- .../myweatherapp/di/remote_datasource_module.kt | 4 ++-- .../domain/repository/DailyForecastRepository.kt | 2 +- .../repository/DailyForecastRepositoryRoomImpl.kt | 4 ++-- .../util/coroutines/ApplicationSchedulerProvider.kt | 11 ++++++----- .../ekito/myweatherapp/util/coroutines/RxWithExt.kt | 4 ++-- .../util/coroutines/SchedulerProvider.kt | 2 +- .../fr/ekito/myweatherapp/util/mvvm/RxViewModel.kt | 4 ++-- .../integration/WeatherRepositoryTest.kt | 1 + .../mock/mvvm/DetailViewModelMockTest.kt | 2 +- .../mock/mvvm/SplashViewModelMockTest.kt | 2 +- .../mock/mvvm/WeatherHeaderViewModelMockTest.kt | 2 +- .../mock/mvvm/WeatherListViewModelMockTest.kt | 2 +- .../java/fr/ekito/myweatherapp/util/RxTestExt.kt | 13 +++++++++++++ .../myweatherapp/util/TestSchedulerProvider.kt | 9 +++++---- gradle/versions-examples.gradle | 2 +- 20 files changed, 48 insertions(+), 32 deletions(-) create mode 100644 examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/util/RxTestExt.kt diff --git a/examples/android-weather-app/build.gradle b/examples/android-weather-app/build.gradle index 7983f48..a98d15e 100644 --- a/examples/android-weather-app/build.gradle +++ b/examples/android-weather-app/build.gradle @@ -72,7 +72,7 @@ dependencies { // Room implementation "androidx.room:room-runtime:$room_version" - implementation "androidx.room:room-rxjava2:$room_version" + implementation "androidx.room:room-rxjava3:$room_version" kapt "androidx.room:room-compiler:$room_version" annotationProcessor "androidx.room:room-compiler:$room_version" testImplementation "androidx.room:room-testing:$room_version" @@ -88,13 +88,13 @@ dependencies { // Networking implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:converter-gson:$retrofit_version" - implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofit_version" + implementation "com.squareup.retrofit2:adapter-rxjava3:$retrofit_version" implementation "com.squareup.okhttp3:okhttp:$okhttp_version" implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version" // Rx - implementation "io.reactivex.rxjava2:rxjava:$rxjava_version" - implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' + implementation "io.reactivex.rxjava3:rxjava:$rxjava_version" + implementation 'io.reactivex.rxjava3:rxandroid:3.0.0' // Canary debugImplementation "com.squareup.leakcanary:leakcanary-android:$leak_canary_version" diff --git a/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/WeatherDAOTest.kt b/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/WeatherDAOTest.kt index 7efd077..5885da8 100644 --- a/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/WeatherDAOTest.kt +++ b/examples/android-weather-app/src/androidTest/java/fr/ekito/myweatherapp/WeatherDAOTest.kt @@ -97,7 +97,7 @@ class WeatherDAOTest : KoinTest { ): List { return weatherWebDatasource.geocode(locationParis) .map { it.getLocation() } - .flatMap { weatherWebDatasource.weather(it.lat, it.lng, "EN") } + .flatMap { weatherWebDatasource.weather(it?.lat, it?.lng, "EN") } .map { it.getDailyForecasts(locationParis) } .map { list -> list.map { WeatherEntity.from(it, dateParis) } } .blockingGet() diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/WeatherDataSource.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/WeatherDataSource.kt index 797bfe3..ce86a16 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/WeatherDataSource.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/WeatherDataSource.kt @@ -2,7 +2,7 @@ package fr.ekito.myweatherapp.data import fr.ekito.myweatherapp.data.json.Geocode import fr.ekito.myweatherapp.data.json.Weather -import io.reactivex.Single +import io.reactivex.rxjava3.core.Single import retrofit2.http.GET import retrofit2.http.Headers import retrofit2.http.Query diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/local/FileDataSource.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/local/FileDataSource.kt index 39aa1c7..c05f249 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/local/FileDataSource.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/local/FileDataSource.kt @@ -3,7 +3,7 @@ package fr.ekito.myweatherapp.data.local import fr.ekito.myweatherapp.data.WeatherDataSource import fr.ekito.myweatherapp.data.json.Geocode import fr.ekito.myweatherapp.data.json.Weather -import io.reactivex.Single +import io.reactivex.rxjava3.core.Single import java.util.Locale import java.util.concurrent.TimeUnit diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/WeatherDAO.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/WeatherDAO.kt index b5cd477..d402288 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/WeatherDAO.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/data/room/WeatherDAO.kt @@ -3,7 +3,7 @@ package fr.ekito.myweatherapp.data.room import androidx.room.Dao import androidx.room.Insert import androidx.room.Query -import io.reactivex.Single +import io.reactivex.rxjava3.core.Single import java.util.Date @Dao diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/di/remote_datasource_module.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/di/remote_datasource_module.kt index 8e03535..c4c7d60 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/di/remote_datasource_module.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/di/remote_datasource_module.kt @@ -6,7 +6,7 @@ import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import org.koin.dsl.module import retrofit2.Retrofit -import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory +import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory import retrofit2.converter.gson.GsonConverterFactory import java.util.concurrent.TimeUnit @@ -38,6 +38,6 @@ inline fun createWebService(okHttpClient: OkHttpClient, url: String) .baseUrl(url) .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build() + .addCallAdapterFactory(RxJava3CallAdapterFactory.create()).build() return retrofit.create(T::class.java) } diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/domain/repository/DailyForecastRepository.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/domain/repository/DailyForecastRepository.kt index 0bc4eb2..1654a0e 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/domain/repository/DailyForecastRepository.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/domain/repository/DailyForecastRepository.kt @@ -4,7 +4,7 @@ import fr.ekito.myweatherapp.data.WeatherDataSource import fr.ekito.myweatherapp.domain.entity.DailyForecast import fr.ekito.myweatherapp.domain.ext.getDailyForecasts import fr.ekito.myweatherapp.domain.ext.getLocation -import io.reactivex.Single +import io.reactivex.rxjava3.core.Single /** * Weather repository diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/domain/repository/DailyForecastRepositoryRoomImpl.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/domain/repository/DailyForecastRepositoryRoomImpl.kt index d800146..6f375ec 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/domain/repository/DailyForecastRepositoryRoomImpl.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/domain/repository/DailyForecastRepositoryRoomImpl.kt @@ -6,8 +6,8 @@ import fr.ekito.myweatherapp.data.room.WeatherEntity import fr.ekito.myweatherapp.domain.entity.DailyForecast import fr.ekito.myweatherapp.domain.ext.getDailyForecasts import fr.ekito.myweatherapp.domain.ext.getLocation -import io.reactivex.Single -import java.util.* +import io.reactivex.rxjava3.core.Single +import java.util.Date class DailyForecastRepositoryRoomImpl( private val weatherDatasource: WeatherDataSource, diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/coroutines/ApplicationSchedulerProvider.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/coroutines/ApplicationSchedulerProvider.kt index cd33db2..4ad9a36 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/coroutines/ApplicationSchedulerProvider.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/coroutines/ApplicationSchedulerProvider.kt @@ -1,15 +1,16 @@ package fr.ekito.myweatherapp.util.coroutines -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.schedulers.Schedulers +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.core.Scheduler +import io.reactivex.rxjava3.schedulers.Schedulers /** * Application providers */ class ApplicationSchedulerProvider : SchedulerProvider { - override fun io() = Schedulers.io() + override fun io(): Scheduler = Schedulers.io() - override fun ui() = AndroidSchedulers.mainThread() + override fun ui(): Scheduler = AndroidSchedulers.mainThread() - override fun computation() = Schedulers.computation() + override fun computation(): Scheduler = Schedulers.computation() } \ No newline at end of file diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/coroutines/RxWithExt.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/coroutines/RxWithExt.kt index 7e323d2..f102f05 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/coroutines/RxWithExt.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/coroutines/RxWithExt.kt @@ -1,7 +1,7 @@ package fr.ekito.myweatherapp.util.coroutines -import io.reactivex.Completable -import io.reactivex.Single +import io.reactivex.rxjava3.core.Completable +import io.reactivex.rxjava3.core.Single /** diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/coroutines/SchedulerProvider.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/coroutines/SchedulerProvider.kt index 13948af..bc3922b 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/coroutines/SchedulerProvider.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/coroutines/SchedulerProvider.kt @@ -1,6 +1,6 @@ package fr.ekito.myweatherapp.util.coroutines -import io.reactivex.Scheduler +import io.reactivex.rxjava3.core.Scheduler /** * Rx Scheduler Provider diff --git a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/mvvm/RxViewModel.kt b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/mvvm/RxViewModel.kt index 6af1028..ec4eacb 100644 --- a/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/mvvm/RxViewModel.kt +++ b/examples/android-weather-app/src/main/kotlin/fr/ekito/myweatherapp/util/mvvm/RxViewModel.kt @@ -2,8 +2,8 @@ package fr.ekito.myweatherapp.util.mvvm import androidx.annotation.CallSuper import androidx.lifecycle.ViewModel -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.disposables.Disposable +import io.reactivex.rxjava3.disposables.CompositeDisposable +import io.reactivex.rxjava3.disposables.Disposable /** * ViewModel for Rx Jobs diff --git a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/integration/WeatherRepositoryTest.kt b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/integration/WeatherRepositoryTest.kt index c8b53fd..044a568 100644 --- a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/integration/WeatherRepositoryTest.kt +++ b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/integration/WeatherRepositoryTest.kt @@ -2,6 +2,7 @@ package fr.ekito.myweatherapp.integration import fr.ekito.myweatherapp.di.testWeatherApp import fr.ekito.myweatherapp.domain.repository.DailyForecastRepository +import fr.ekito.myweatherapp.util.awaitTerminalEvent import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertNotSame diff --git a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/DetailViewModelMockTest.kt b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/DetailViewModelMockTest.kt index e51b796..4bcfd9f 100644 --- a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/DetailViewModelMockTest.kt +++ b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/DetailViewModelMockTest.kt @@ -9,7 +9,7 @@ import fr.ekito.myweatherapp.view.Failed import fr.ekito.myweatherapp.view.Loading import fr.ekito.myweatherapp.view.ViewModelState import fr.ekito.myweatherapp.view.detail.DetailViewModel -import io.reactivex.Single +import io.reactivex.rxjava3.core.Single import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Rule diff --git a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/SplashViewModelMockTest.kt b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/SplashViewModelMockTest.kt index 53cb684..9c15027 100644 --- a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/SplashViewModelMockTest.kt +++ b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/SplashViewModelMockTest.kt @@ -10,7 +10,7 @@ import fr.ekito.myweatherapp.view.Pending import fr.ekito.myweatherapp.view.Success import fr.ekito.myweatherapp.view.ViewModelEvent import fr.ekito.myweatherapp.view.splash.SplashViewModel -import io.reactivex.Single +import io.reactivex.rxjava3.core.Single import org.junit.Assert import org.junit.Before import org.junit.Rule diff --git a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/WeatherHeaderViewModelMockTest.kt b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/WeatherHeaderViewModelMockTest.kt index 559af90..8fa408f 100644 --- a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/WeatherHeaderViewModelMockTest.kt +++ b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/WeatherHeaderViewModelMockTest.kt @@ -11,7 +11,7 @@ import fr.ekito.myweatherapp.view.Loading import fr.ekito.myweatherapp.view.ViewModelEvent import fr.ekito.myweatherapp.view.ViewModelState import fr.ekito.myweatherapp.view.weather.WeatherViewModel -import io.reactivex.Single +import io.reactivex.rxjava3.core.Single import org.junit.Assert import org.junit.Before import org.junit.Rule diff --git a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/WeatherListViewModelMockTest.kt b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/WeatherListViewModelMockTest.kt index 464e33b..d3ecb3e 100644 --- a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/WeatherListViewModelMockTest.kt +++ b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/mock/mvvm/WeatherListViewModelMockTest.kt @@ -9,7 +9,7 @@ import fr.ekito.myweatherapp.view.Failed import fr.ekito.myweatherapp.view.Loading import fr.ekito.myweatherapp.view.ViewModelState import fr.ekito.myweatherapp.view.weather.WeatherViewModel -import io.reactivex.Single +import io.reactivex.rxjava3.core.Single import org.junit.Assert import org.junit.Before import org.junit.Rule diff --git a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/util/RxTestExt.kt b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/util/RxTestExt.kt new file mode 100644 index 0000000..f0dd905 --- /dev/null +++ b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/util/RxTestExt.kt @@ -0,0 +1,13 @@ +package fr.ekito.myweatherapp.util + +import io.reactivex.rxjava3.observers.TestObserver + +fun TestObserver.awaitTerminalEvent(): Boolean { + return try { + this.await() + true + } catch (ex: InterruptedException) { + Thread.currentThread().interrupt() + false + } +} \ No newline at end of file diff --git a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/util/TestSchedulerProvider.kt b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/util/TestSchedulerProvider.kt index 59d182f..a24b9b1 100644 --- a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/util/TestSchedulerProvider.kt +++ b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/util/TestSchedulerProvider.kt @@ -1,12 +1,13 @@ package fr.ekito.myweatherapp.util -import io.reactivex.schedulers.Schedulers +import io.reactivex.rxjava3.schedulers.Schedulers import fr.ekito.myweatherapp.util.coroutines.SchedulerProvider +import io.reactivex.rxjava3.core.Scheduler class TestSchedulerProvider : SchedulerProvider { - override fun io() = Schedulers.trampoline() + override fun io(): Scheduler = Schedulers.trampoline() - override fun ui() = Schedulers.trampoline() + override fun ui(): Scheduler = Schedulers.trampoline() - override fun computation() = Schedulers.trampoline() + override fun computation(): Scheduler = Schedulers.trampoline() } \ No newline at end of file diff --git a/gradle/versions-examples.gradle b/gradle/versions-examples.gradle index c7444cb..f8c47d6 100644 --- a/gradle/versions-examples.gradle +++ b/gradle/versions-examples.gradle @@ -9,5 +9,5 @@ ext { anko_version='0.10.4' okhttp_version = '4.9.1' retrofit_version = '2.9.0' - rxjava_version = '2.2.21' + rxjava_version = '3.1.0' } \ No newline at end of file From 0514d52487a66d20465df2658879590375aa9aaf Mon Sep 17 00:00:00 2001 From: wiryadev Date: Sun, 15 Aug 2021 15:46:37 +0700 Subject: [PATCH 13/18] remove android support library version --- gradle/versions-android.gradle | 2 -- gradle/versions-examples.gradle | 1 - 2 files changed, 3 deletions(-) diff --git a/gradle/versions-android.gradle b/gradle/versions-android.gradle index 9536b36..b39afde 100644 --- a/gradle/versions-android.gradle +++ b/gradle/versions-android.gradle @@ -5,8 +5,6 @@ ext { android_gradle_version = "7.0.0" android_build_tools_version = '30.0.2' - support_lib_version = "28.0.0" - androidx_lib_version = "1.0.2" arch_version = "2.1.0" lifecycle_version = '2.3.1' diff --git a/gradle/versions-examples.gradle b/gradle/versions-examples.gradle index f8c47d6..57e673b 100644 --- a/gradle/versions-examples.gradle +++ b/gradle/versions-examples.gradle @@ -1,6 +1,5 @@ ext { // Android Support - support_lib_version = "28.0.0" constraint_layout_version = "2.1.0" room_version = "2.3.0" From 95273b4d6a7a390bb6f1283c70b9c31e8e4883a4 Mon Sep 17 00:00:00 2001 From: wiryadev Date: Wed, 13 Oct 2021 11:01:03 +0700 Subject: [PATCH 14/18] dependencies update for Kotlin, RxJava, and ConstraintLayout --- examples/android-weather-app/build.gradle | 2 +- gradle/versions-examples.gradle | 4 ++-- gradle/versions.gradle | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/android-weather-app/build.gradle b/examples/android-weather-app/build.gradle index a98d15e..ded861b 100644 --- a/examples/android-weather-app/build.gradle +++ b/examples/android-weather-app/build.gradle @@ -83,7 +83,7 @@ dependencies { implementation 'com.joanzapata.iconify:android-iconify-weathericons:2.2.2' // Gson - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.8.8' // Networking implementation "com.squareup.retrofit2:retrofit:$retrofit_version" diff --git a/gradle/versions-examples.gradle b/gradle/versions-examples.gradle index 57e673b..863235e 100644 --- a/gradle/versions-examples.gradle +++ b/gradle/versions-examples.gradle @@ -1,6 +1,6 @@ ext { // Android Support - constraint_layout_version = "2.1.0" + constraint_layout_version = "2.1.1" room_version = "2.3.0" leak_canary_version = "2.7" @@ -8,5 +8,5 @@ ext { anko_version='0.10.4' okhttp_version = '4.9.1' retrofit_version = '2.9.0' - rxjava_version = '3.1.0' + rxjava_version = '3.1.2' } \ No newline at end of file diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 8f4da5e..68914c8 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -3,8 +3,8 @@ ext { koin_version = '3.1.2' // Kotlin - kotlin_version = '1.5.21' - coroutines_version = "1.5.1" + kotlin_version = '1.5.31' + coroutines_version = "1.5.2" // Dokka dokka_version = '0.9.16' From 8e1d96fbccd8459f5a619f08178b312dc96d86da Mon Sep 17 00:00:00 2001 From: wiryadev Date: Wed, 13 Oct 2021 11:05:06 +0700 Subject: [PATCH 15/18] update gradle version --- gradle/versions-android.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/versions-android.gradle b/gradle/versions-android.gradle index b39afde..c70fd89 100644 --- a/gradle/versions-android.gradle +++ b/gradle/versions-android.gradle @@ -3,7 +3,7 @@ ext { android_min_version = 21 android_target_version = 30 - android_gradle_version = "7.0.0" + android_gradle_version = '7.0.3' android_build_tools_version = '30.0.2' arch_version = "2.1.0" From 86eb11670ff2c45f097ed31880aa54646b0b5738 Mon Sep 17 00:00:00 2001 From: wiryadev Date: Fri, 29 Oct 2021 20:59:41 +0700 Subject: [PATCH 16/18] bump build tools and koin version --- gradle/versions-android.gradle | 2 +- gradle/versions.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/versions-android.gradle b/gradle/versions-android.gradle index c70fd89..6fab2a6 100644 --- a/gradle/versions-android.gradle +++ b/gradle/versions-android.gradle @@ -4,7 +4,7 @@ ext { android_target_version = 30 android_gradle_version = '7.0.3' - android_build_tools_version = '30.0.2' + android_build_tools_version = '30.0.3' arch_version = "2.1.0" lifecycle_version = '2.3.1' diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 68914c8..0218079 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -1,6 +1,6 @@ ext { // Koin - koin_version = '3.1.2' + koin_version = '3.1.3' // Kotlin kotlin_version = '1.5.31' From b440f121799ed29d9ab8d0a01d56bf1c1b82ba44 Mon Sep 17 00:00:00 2001 From: wiryadev Date: Fri, 29 Oct 2021 21:19:50 +0700 Subject: [PATCH 17/18] bump lifecycle and targetSdk version and set exported for launcher activity --- examples/android-weather-app/src/main/AndroidManifest.xml | 3 ++- gradle/versions-android.gradle | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/android-weather-app/src/main/AndroidManifest.xml b/examples/android-weather-app/src/main/AndroidManifest.xml index 238efed..0f300d8 100644 --- a/examples/android-weather-app/src/main/AndroidManifest.xml +++ b/examples/android-weather-app/src/main/AndroidManifest.xml @@ -13,7 +13,8 @@ android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> - + diff --git a/gradle/versions-android.gradle b/gradle/versions-android.gradle index 6fab2a6..c7ada60 100644 --- a/gradle/versions-android.gradle +++ b/gradle/versions-android.gradle @@ -1,11 +1,11 @@ ext { // Sdk and tools android_min_version = 21 - android_target_version = 30 + android_target_version = 31 android_gradle_version = '7.0.3' android_build_tools_version = '30.0.3' arch_version = "2.1.0" - lifecycle_version = '2.3.1' + lifecycle_version = '2.4.0' } \ No newline at end of file From 61d0df88a7f6b2f78b236e3eb67672d4efdf42d0 Mon Sep 17 00:00:00 2001 From: wiryadev Date: Fri, 29 Oct 2021 21:20:24 +0700 Subject: [PATCH 18/18] replace deprecated `create` with `withParameter` --- .../test/java/fr/ekito/myweatherapp/ModuleCheckTest.kt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/ModuleCheckTest.kt b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/ModuleCheckTest.kt index 00761b6..dfbe458 100644 --- a/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/ModuleCheckTest.kt +++ b/examples/android-weather-app/src/test/java/fr/ekito/myweatherapp/ModuleCheckTest.kt @@ -9,7 +9,6 @@ import fr.ekito.myweatherapp.view.detail.DetailViewModel import org.junit.Test import org.koin.android.ext.koin.androidContext import org.koin.core.logger.Level -import org.koin.core.parameter.parametersOf import org.koin.dsl.koinApplication import org.koin.fileProperties import org.koin.test.KoinTest @@ -31,7 +30,7 @@ class ModuleCheckTest : KoinTest { androidContext(mockedAndroidContext) modules(onlineWeatherApp) }.checkModules { - create { parametersOf(viewModelId) } + withParameter { viewModelId } } } @@ -41,7 +40,7 @@ class ModuleCheckTest : KoinTest { androidContext(mockedAndroidContext) modules(offlineWeatherApp) }.checkModules { - create { parametersOf(viewModelId) } + withParameter { viewModelId } } } @@ -52,7 +51,7 @@ class ModuleCheckTest : KoinTest { androidContext(mockedAndroidContext) modules(testWeatherApp) }.checkModules { - create { parametersOf(viewModelId) } + withParameter { viewModelId } } } @@ -62,7 +61,7 @@ class ModuleCheckTest : KoinTest { androidContext(mockedAndroidContext) modules(roomWeatherApp) }.checkModules { - create { parametersOf(viewModelId) } + withParameter { viewModelId } } } }