From 28f3a37ea67eb3058431d415c008ef34357012b8 Mon Sep 17 00:00:00 2001 From: Pavel Akashev Date: Wed, 23 Apr 2025 19:49:58 +0300 Subject: [PATCH 1/9] fix CatsViewModelFactory --- flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt b/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt index 0d8ba8a7..e17574bf 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt @@ -26,6 +26,7 @@ class CatsViewModel( class CatsViewModelFactory(private val catsRepository: CatsRepository) : ViewModelProvider.NewInstanceFactory() { - override fun create(modelClass: Class): T = + @Suppress("UNCHECKED_CAST") + override fun create(modelClass: Class): T = CatsViewModel(catsRepository) as T } \ No newline at end of file From 0ede7f8e67c904a9ddb0a68718c256d56f83bb68 Mon Sep 17 00:00:00 2001 From: Pavel Akashev Date: Wed, 23 Apr 2025 20:14:13 +0300 Subject: [PATCH 2/9] fix base url --- .../otus/homework/flowcats/CatsService.kt | 2 +- .../java/otus/homework/flowcats/CatsView.kt | 2 +- .../otus/homework/flowcats/DiContainer.kt | 2 +- .../main/java/otus/homework/flowcats/Fact.kt | 22 ++++--------------- 4 files changed, 7 insertions(+), 21 deletions(-) diff --git a/flowcats/src/main/java/otus/homework/flowcats/CatsService.kt b/flowcats/src/main/java/otus/homework/flowcats/CatsService.kt index 25192882..787829a1 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/CatsService.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/CatsService.kt @@ -4,6 +4,6 @@ import retrofit2.http.GET interface CatsService { - @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..eba22638 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/CatsView.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/CatsView.kt @@ -12,7 +12,7 @@ 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 } } diff --git a/flowcats/src/main/java/otus/homework/flowcats/DiContainer.kt b/flowcats/src/main/java/otus/homework/flowcats/DiContainer.kt index 485152e2..479958b5 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/DiContainer.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/DiContainer.kt @@ -7,7 +7,7 @@ class DiContainer { private val retrofit by lazy { Retrofit.Builder() - .baseUrl("https://cat-fact.herokuapp.com/facts/") + .baseUrl("https://catfact.ninja/") .addConverterFactory(GsonConverterFactory.create()) .build() } diff --git a/flowcats/src/main/java/otus/homework/flowcats/Fact.kt b/flowcats/src/main/java/otus/homework/flowcats/Fact.kt index 602303eb..81998454 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/Fact.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/Fact.kt @@ -3,22 +3,8 @@ 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("fact") + val fact: String, + @field:SerializedName("length") + val length: Int ) \ No newline at end of file From c6795be47274324f8656b862fa2442755ead793b Mon Sep 17 00:00:00 2001 From: Pavel Akashev Date: Wed, 23 Apr 2025 20:14:26 +0300 Subject: [PATCH 3/9] fix crash --- .../otus/homework/flowcats/CatsViewModel.kt | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt b/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt index e17574bf..bcf73bbb 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt @@ -2,9 +2,9 @@ package otus.homework.flowcats import androidx.lifecycle.* import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach class CatsViewModel( private val catsRepository: CatsRepository @@ -14,13 +14,11 @@ class CatsViewModel( val catsLiveData: LiveData = _catsLiveData init { - viewModelScope.launch { - withContext(Dispatchers.IO) { - catsRepository.listenForCatFacts().collect { - _catsLiveData.value = it - } - } - } + catsRepository.listenForCatFacts() + .flowOn(Dispatchers.IO) + .onEach { + _catsLiveData.value = it + }.launchIn(viewModelScope) } } From 2953f7f524c35d099a4287d1edd15fadb064c008 Mon Sep 17 00:00:00 2001 From: Pavel Akashev Date: Thu, 24 Apr 2025 00:52:55 +0300 Subject: [PATCH 4/9] added Result --- flowcats/src/main/java/otus/homework/flowcats/Result.kt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 flowcats/src/main/java/otus/homework/flowcats/Result.kt 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..7f4419b2 --- /dev/null +++ b/flowcats/src/main/java/otus/homework/flowcats/Result.kt @@ -0,0 +1,8 @@ +package otus.homework.flowcats + +typealias BaseError = Error + +sealed interface Result { + data class Success(val data: D) : Result + data class Error(val error: Throwable) : Result +} \ No newline at end of file From 66f6505bcca1cdc4408e14c34a5855d26f247b10 Mon Sep 17 00:00:00 2001 From: Pavel Akashev Date: Thu, 24 Apr 2025 01:17:52 +0300 Subject: [PATCH 5/9] refactored LiveData to StateFlow --- .../otus/homework/flowcats/CatsRepository.kt | 11 +++++++--- .../otus/homework/flowcats/CatsViewModel.kt | 9 ++++++--- .../main/java/otus/homework/flowcats/Fact.kt | 4 ++-- .../otus/homework/flowcats/MainActivity.kt | 20 ++++++++++++++++--- .../java/otus/homework/flowcats/Result.kt | 4 +--- flowcats/src/main/res/values/strings.xml | 2 ++ 6 files changed, 36 insertions(+), 14 deletions(-) diff --git a/flowcats/src/main/java/otus/homework/flowcats/CatsRepository.kt b/flowcats/src/main/java/otus/homework/flowcats/CatsRepository.kt index 10fcb77d..82622c34 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/CatsRepository.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/CatsRepository.kt @@ -1,6 +1,7 @@ package otus.homework.flowcats import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow class CatsRepository( @@ -8,10 +9,14 @@ class CatsRepository( private val refreshIntervalMs: Long = 5000 ) { - fun listenForCatFacts() = flow { + fun listenForCatFacts(): Flow> = flow { while (true) { - val latestNews = catsService.getCatFact() - emit(latestNews) + try { + val latestNews = catsService.getCatFact() + emit(Result.Success(latestNews)) + } catch (e: Exception) { + emit(Result.Error(e)) + } delay(refreshIntervalMs) } } diff --git a/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt b/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt index bcf73bbb..3a6a91ca 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt @@ -2,6 +2,9 @@ package otus.homework.flowcats import androidx.lifecycle.* import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -10,14 +13,14 @@ class CatsViewModel( private val catsRepository: CatsRepository ) : ViewModel() { - private val _catsLiveData = MutableLiveData() - val catsLiveData: LiveData = _catsLiveData + private val _cats = MutableStateFlow>(Result.Success(Fact())) + val cats: StateFlow> = _cats.asStateFlow() init { catsRepository.listenForCatFacts() .flowOn(Dispatchers.IO) .onEach { - _catsLiveData.value = it + _cats.value = it }.launchIn(viewModelScope) } } diff --git a/flowcats/src/main/java/otus/homework/flowcats/Fact.kt b/flowcats/src/main/java/otus/homework/flowcats/Fact.kt index 81998454..481960c5 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/Fact.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/Fact.kt @@ -4,7 +4,7 @@ import com.google.gson.annotations.SerializedName data class Fact( @field:SerializedName("fact") - val fact: String, + val fact: String = "", @field:SerializedName("length") - val length: Int + val length: Int = 0 ) \ 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..ed1aa70c 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt @@ -2,7 +2,12 @@ package otus.homework.flowcats import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import android.widget.Toast import androidx.activity.viewModels +import androidx.lifecycle.lifecycleScope +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import java.net.SocketTimeoutException class MainActivity : AppCompatActivity() { @@ -14,8 +19,17 @@ class MainActivity : AppCompatActivity() { val view = layoutInflater.inflate(R.layout.activity_main, null) as CatsView setContentView(view) - catsViewModel.catsLiveData.observe(this){ - view.populate(it) - } + catsViewModel.cats.onEach { + when (it) { + is Result.Error -> { + val message = when(it.error) { + is SocketTimeoutException -> R.string.socket_timeout + else -> {R.string.unknown} + } + Toast.makeText(this, message, Toast.LENGTH_LONG).show() + } + is Result.Success -> view.populate(it.data) + } + }.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 index 7f4419b2..9f1ea181 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/Result.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/Result.kt @@ -1,8 +1,6 @@ package otus.homework.flowcats -typealias BaseError = Error - sealed interface Result { data class Success(val data: D) : Result - data class Error(val error: Throwable) : Result + data class Error(val error: Throwable) : 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..aa9b73bf 100644 --- a/flowcats/src/main/res/values/strings.xml +++ b/flowcats/src/main/res/values/strings.xml @@ -1,3 +1,5 @@ Flow cats + Не удалось получить ответ от сервера + Неизвестная ошибка \ No newline at end of file From a9837b482fea5915babc8482068bc5650402db2b Mon Sep 17 00:00:00 2001 From: Pavel Akashev Date: Thu, 24 Apr 2025 01:47:20 +0300 Subject: [PATCH 6/9] task1 --- .../src/main/java/otus/homework/flow/SampleInteractor.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/operators/src/main/java/otus/homework/flow/SampleInteractor.kt b/operators/src/main/java/otus/homework/flow/SampleInteractor.kt index 1993c064..a75e417e 100644 --- a/operators/src/main/java/otus/homework/flow/SampleInteractor.kt +++ b/operators/src/main/java/otus/homework/flow/SampleInteractor.kt @@ -18,7 +18,11 @@ class SampleInteractor( * 6) возвращает результат */ fun task1(): Flow { - return flowOf() + return sampleRepository.produceNumbers() + .map { it * 5 } + .filterNot { it <= 20 || it % 2 == 0 } + .map { "$it won" } + .take(3) } /** From edeed13ef057611b9b8c361a2515f7b0bf8583c2 Mon Sep 17 00:00:00 2001 From: Pavel Akashev Date: Thu, 24 Apr 2025 02:08:17 +0300 Subject: [PATCH 7/9] task2 --- .../main/java/otus/homework/flow/SampleInteractor.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/operators/src/main/java/otus/homework/flow/SampleInteractor.kt b/operators/src/main/java/otus/homework/flow/SampleInteractor.kt index a75e417e..dc17fb1b 100644 --- a/operators/src/main/java/otus/homework/flow/SampleInteractor.kt +++ b/operators/src/main/java/otus/homework/flow/SampleInteractor.kt @@ -33,7 +33,15 @@ class SampleInteractor( * Если число не делится на 3,5,15 - эмитим само число */ fun task2(): Flow { - return flowOf() + return sampleRepository.produceNumbers() + .flatMapConcat { num -> + when { + num % 15 == 0 -> flowOf("$num", "FizzBuzz") + num % 3 == 0 -> flowOf("$num", "Fizz") + num % 5 == 0 -> flowOf("$num", "Buzz") + else -> flowOf("$num") + } + } } /** From 66050086d0be91a5b21a4712b070d10011ebf5b0 Mon Sep 17 00:00:00 2001 From: Pavel Akashev Date: Thu, 24 Apr 2025 02:15:31 +0300 Subject: [PATCH 8/9] task3 --- .../otus/homework/flow/SampleInteractor.kt | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/operators/src/main/java/otus/homework/flow/SampleInteractor.kt b/operators/src/main/java/otus/homework/flow/SampleInteractor.kt index dc17fb1b..ef0c64eb 100644 --- a/operators/src/main/java/otus/homework/flow/SampleInteractor.kt +++ b/operators/src/main/java/otus/homework/flow/SampleInteractor.kt @@ -18,11 +18,8 @@ class SampleInteractor( * 6) возвращает результат */ fun task1(): Flow { - return sampleRepository.produceNumbers() - .map { it * 5 } - .filterNot { it <= 20 || it % 2 == 0 } - .map { "$it won" } - .take(3) + return sampleRepository.produceNumbers().map { it * 5 } + .filterNot { it <= 20 || it % 2 == 0 }.map { "$it won" }.take(3) } /** @@ -33,15 +30,14 @@ class SampleInteractor( * Если число не делится на 3,5,15 - эмитим само число */ fun task2(): Flow { - return sampleRepository.produceNumbers() - .flatMapConcat { num -> - when { - num % 15 == 0 -> flowOf("$num", "FizzBuzz") - num % 3 == 0 -> flowOf("$num", "Fizz") - num % 5 == 0 -> flowOf("$num", "Buzz") - else -> flowOf("$num") - } + return sampleRepository.produceNumbers().flatMapConcat { num -> + when { + num % 15 == 0 -> flowOf("$num", "FizzBuzz") + num % 3 == 0 -> flowOf("$num", "Fizz") + num % 5 == 0 -> flowOf("$num", "Buzz") + else -> flowOf("$num") } + } } /** @@ -50,7 +46,9 @@ class SampleInteractor( * Если айтемы в одно из флоу кончились то результирующий флоу также должен закончится */ fun task3(): Flow> { - return flowOf() + return sampleRepository.produceColors().zip(sampleRepository.produceForms()) { color, form -> + color to form + } } /** From c0cf9ce2173c2d117225a544e93d52b021320c30 Mon Sep 17 00:00:00 2001 From: Pavel Akashev Date: Thu, 24 Apr 2025 15:50:37 +0300 Subject: [PATCH 9/9] task4 --- .../src/main/java/otus/homework/flow/SampleInteractor.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/operators/src/main/java/otus/homework/flow/SampleInteractor.kt b/operators/src/main/java/otus/homework/flow/SampleInteractor.kt index ef0c64eb..b8a4b560 100644 --- a/operators/src/main/java/otus/homework/flow/SampleInteractor.kt +++ b/operators/src/main/java/otus/homework/flow/SampleInteractor.kt @@ -58,6 +58,11 @@ class SampleInteractor( * При любом исходе, будь то выброс исключения или успешная отработка функции вызовите метод dotsRepository.completed() */ fun task4(): Flow { - return flowOf() + return sampleRepository.produceNumbers() + .catch { cause: Throwable -> + if (cause is IllegalArgumentException) emit(-1) + else throw cause + } + .onCompletion { sampleRepository.completed() } } } \ No newline at end of file