diff --git a/flowcats/build.gradle b/flowcats/build.gradle index 0ea35e68..3788cea3 100644 --- a/flowcats/build.gradle +++ b/flowcats/build.gradle @@ -4,15 +4,15 @@ plugins { } android { - compileSdkVersion 30 - buildToolsVersion "30.0.3" + compileSdk 34 + buildToolsVersion "34.0.0" namespace = "otus.homework.flowcats" defaultConfig { applicationId "otus.homework.flowcats" minSdkVersion 23 - targetSdkVersion 30 + targetSdkVersion 33 versionCode 1 versionName "1.0" diff --git a/flowcats/src/main/AndroidManifest.xml b/flowcats/src/main/AndroidManifest.xml index 2deb6454..6531e25f 100644 --- a/flowcats/src/main/AndroidManifest.xml +++ b/flowcats/src/main/AndroidManifest.xml @@ -10,7 +10,8 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Flow" > - + diff --git a/flowcats/src/main/java/otus/homework/flowcats/CatsRepository.kt b/flowcats/src/main/java/otus/homework/flowcats/CatsRepository.kt index 10fcb77d..a377712b 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/CatsRepository.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/CatsRepository.kt @@ -1,7 +1,10 @@ package otus.homework.flowcats +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn + class CatsRepository( private val catsService: CatsService, @@ -11,8 +14,8 @@ class CatsRepository( fun listenForCatFacts() = flow { while (true) { val latestNews = catsService.getCatFact() - emit(latestNews) - delay(refreshIntervalMs) + emit (latestNews) + delay (refreshIntervalMs) } - } + }.flowOn(Dispatchers.IO) } \ No newline at end of file diff --git a/flowcats/src/main/java/otus/homework/flowcats/CatsService.kt b/flowcats/src/main/java/otus/homework/flowcats/CatsService.kt index 25192882..2a357324 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/CatsService.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/CatsService.kt @@ -4,6 +4,7 @@ import retrofit2.http.GET interface CatsService { - @GET("random?animal_type=cat") - suspend fun getCatFact(): Fact +// @GET("random?animal_type=cat") + @GET("fact") + suspend fun getCatFact(): Fact } \ No newline at end of file diff --git a/flowcats/src/main/java/otus/homework/flowcats/CatsView.kt b/flowcats/src/main/java/otus/homework/flowcats/CatsView.kt index 6a195f3a..8080b185 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/CatsView.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/CatsView.kt @@ -3,8 +3,10 @@ package otus.homework.flowcats import android.content.Context import android.util.AttributeSet import android.widget.TextView +import android.widget.Toast import androidx.constraintlayout.widget.ConstraintLayout + class CatsView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, @@ -12,11 +14,22 @@ class CatsView @JvmOverloads constructor( ) : ConstraintLayout(context, attrs, defStyleAttr), ICatsView { override fun populate(fact: Fact) { - findViewById(R.id.fact_textView).text = fact.text + findViewById(R.id.fact_textView).text = fact.fact + } + + override fun showError(message: String?) { + Toast.makeText(context, message ?: context.getText(R.string.error), Toast.LENGTH_LONG) + .show() + } + + override fun load() { + findViewById(R.id.fact_textView).text = context.getText(R.string.loading) } } interface ICatsView { fun populate(fact: Fact) + fun showError(message: String?) + fun load() } \ No newline at end of file diff --git a/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt b/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt index 0d8ba8a7..1c17d301 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt @@ -1,31 +1,38 @@ package otus.homework.flowcats import androidx.lifecycle.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext +import kotlinx.coroutines.flow.onEach + class CatsViewModel( private val catsRepository: CatsRepository ) : ViewModel() { - private val _catsLiveData = MutableLiveData() - val catsLiveData: LiveData = _catsLiveData + private val _catsFlow = MutableStateFlow(Result.Initial) + val catsFlow: StateFlow = _catsFlow.asStateFlow() init { - viewModelScope.launch { - withContext(Dispatchers.IO) { - catsRepository.listenForCatFacts().collect { - _catsLiveData.value = it +// viewModelScope.launch { + catsRepository.listenForCatFacts() + .onEach {_catsFlow.value = Result.Success(it)} + .catch { _catsFlow.value = Result.Error(it.message.toString()) } + .launchIn(viewModelScope) + } - } } - } -} + + + + class CatsViewModelFactory(private val catsRepository: CatsRepository) : - ViewModelProvider.NewInstanceFactory() { - override fun create(modelClass: Class): T = - CatsViewModel(catsRepository) as T + ViewModelProvider.Factory { + override fun create(modelClass: Class): T = + modelClass.getConstructor(CatsRepository::class.java).newInstance(catsRepository) } \ No newline at end of file diff --git a/flowcats/src/main/java/otus/homework/flowcats/DiContainer.kt b/flowcats/src/main/java/otus/homework/flowcats/DiContainer.kt index 485152e2..cef2a195 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/DiContainer.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/DiContainer.kt @@ -7,12 +7,12 @@ class DiContainer { private val retrofit by lazy { Retrofit.Builder() - .baseUrl("https://cat-fact.herokuapp.com/facts/") + .baseUrl("https://catfact.ninja/") .addConverterFactory(GsonConverterFactory.create()) .build() } - val service by lazy { retrofit.create(CatsService::class.java) } + val service: CatsService by lazy { retrofit.create(CatsService::class.java) } val repository by lazy { CatsRepository(service) } } \ No newline at end of file diff --git a/flowcats/src/main/java/otus/homework/flowcats/Fact.kt b/flowcats/src/main/java/otus/homework/flowcats/Fact.kt index 602303eb..c78684ef 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/Fact.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/Fact.kt @@ -3,22 +3,26 @@ package otus.homework.flowcats import com.google.gson.annotations.SerializedName data class Fact( - @field:SerializedName("createdAt") - val createdAt: String, - @field:SerializedName("deleted") - val deleted: Boolean, - @field:SerializedName("_id") - val id: String, - @field:SerializedName("text") - val text: String, - @field:SerializedName("source") - val source: String, - @field:SerializedName("used") - val used: Boolean, - @field:SerializedName("type") - val type: String, - @field:SerializedName("user") - val user: String, - @field:SerializedName("updatedAt") - val updatedAt: String +// @field:SerializedName("createdAt") +// val createdAt: String, +// @field:SerializedName("deleted") +// val deleted: Boolean, +// @field:SerializedName("_id") +// val id: String, +// @field:SerializedName("text") +// val text: String, +// @field:SerializedName("source") +// val source: String, +// @field:SerializedName("used") +// val used: Boolean, +// @field:SerializedName("type") +// val type: String, +// @field:SerializedName("user") +// val user: String, +// @field:SerializedName("updatedAt") +// val updatedAt: String, + @field:SerializedName("fact") + val fact: String, + @field:SerializedName("length") + val length: Int ) \ No newline at end of file diff --git a/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt b/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt index edea434b..6b0e0552 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt @@ -3,19 +3,28 @@ package otus.homework.flowcats import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import androidx.activity.viewModels +import androidx.lifecycle.lifecycleScope +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach + class MainActivity : AppCompatActivity() { private val diContainer = DiContainer() - private val catsViewModel by viewModels { CatsViewModelFactory(diContainer.repository) } + private val catsViewModel by viewModels { + CatsViewModelFactory(diContainer.repository) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val view = layoutInflater.inflate(R.layout.activity_main, null) as CatsView setContentView(view) - catsViewModel.catsLiveData.observe(this){ - view.populate(it) - } + catsViewModel.catsFlow.onEach{ + when (it) { + is Result.Initial -> view.load() + is Result.Success -> {view.populate(it.fact)} + is Result.Error -> view.showError(it.errorMsg) + } + }.launchIn(lifecycleScope) } } \ No newline at end of file diff --git a/flowcats/src/main/java/otus/homework/flowcats/Result.kt b/flowcats/src/main/java/otus/homework/flowcats/Result.kt new file mode 100644 index 00000000..1bb515da --- /dev/null +++ b/flowcats/src/main/java/otus/homework/flowcats/Result.kt @@ -0,0 +1,7 @@ +package otus.homework.flowcats + +sealed class Result { + data class Success(val fact: Fact) : Result() + data class Error(val errorMsg: String?) : Result() + data object Initial: Result() +} \ No newline at end of file diff --git a/flowcats/src/main/res/values/strings.xml b/flowcats/src/main/res/values/strings.xml index ba737b82..b3c794de 100644 --- a/flowcats/src/main/res/values/strings.xml +++ b/flowcats/src/main/res/values/strings.xml @@ -1,3 +1,5 @@ Flow cats + Error + Loading… \ No newline at end of file diff --git a/operators/src/main/java/otus/homework/flow/SampleInteractor.kt b/operators/src/main/java/otus/homework/flow/SampleInteractor.kt index 1993c064..de75b2a6 100644 --- a/operators/src/main/java/otus/homework/flow/SampleInteractor.kt +++ b/operators/src/main/java/otus/homework/flow/SampleInteractor.kt @@ -18,7 +18,12 @@ class SampleInteractor( * 6) возвращает результат */ fun task1(): Flow { - return flowOf() + return sampleRepository.produceNumbers() + .map { it * 5 } + .filter { it > 20 } + .filter { it % 2 != 0 } + .map { "$it won" } + .take(3) } /** @@ -29,7 +34,16 @@ class SampleInteractor( * Если число не делится на 3,5,15 - эмитим само число */ fun task2(): Flow { - return flowOf() + return sampleRepository.produceNumbers() + .transform { + emit(it.toString()) + + when { + it % 15 == 0 -> emit("FizzBuzz") + it % 5 == 0 -> emit("Buzz") + it % 3 == 0 -> emit("Fizz") + } + } } /** @@ -38,7 +52,10 @@ class SampleInteractor( * Если айтемы в одно из флоу кончились то результирующий флоу также должен закончится */ fun task3(): Flow> { - return flowOf() + return sampleRepository.produceColors() + .zip(sampleRepository.produceForms()) { color, form -> + Pair(color, form) + } } /** @@ -48,6 +65,12 @@ class SampleInteractor( * При любом исходе, будь то выброс исключения или успешная отработка функции вызовите метод dotsRepository.completed() */ fun task4(): Flow { - return flowOf() + return sampleRepository.produceNumbers() + .catch { + if (it is IllegalArgumentException) emit(-1) + else throw it + }.onCompletion { + sampleRepository.completed() + } } } \ No newline at end of file