diff --git a/flowcats/src/main/java/otus/homework/flowcats/CatsRepository.kt b/flowcats/src/main/java/otus/homework/flowcats/CatsRepository.kt index 10fcb77d..b982a983 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/CatsRepository.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/CatsRepository.kt @@ -1,7 +1,9 @@ package otus.homework.flowcats import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.onStart class CatsRepository( private val catsService: CatsService, @@ -11,8 +13,19 @@ class CatsRepository( fun listenForCatFacts() = flow { while (true) { val latestNews = catsService.getCatFact() - emit(latestNews) + if (latestNews.isSuccessful && latestNews.body() != null) + emit(Result.Success(latestNews.body()!!)) + else emit(Result.Error(latestNews.message())) delay(refreshIntervalMs) } - } + }.onStart { + emit(Result.Loading) + }.catch { error -> + emit( + Result.Error( + error.message ?: error.localizedMessage + ?: "Непредвиденная ошибка. Обратитесь к разработчикам" + ) + ) + } } \ 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..8461e0fb 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/CatsService.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/CatsService.kt @@ -1,9 +1,10 @@ package otus.homework.flowcats import retrofit2.http.GET +import retrofit2.Response interface CatsService { - @GET("random?animal_type=cat") - suspend fun getCatFact(): Fact + @GET("fact") + suspend fun getCatFact(): Response } \ 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/CatsViewModel.kt b/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt index 0d8ba8a7..213a86dc 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/CatsViewModel.kt @@ -1,7 +1,12 @@ package otus.homework.flowcats -import androidx.lifecycle.* +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -10,8 +15,8 @@ class CatsViewModel( private val catsRepository: CatsRepository ) : ViewModel() { - private val _catsLiveData = MutableLiveData() - val catsLiveData: LiveData = _catsLiveData + private val _catsLiveData: MutableStateFlow = MutableStateFlow(null) + val catsLiveData: StateFlow = _catsLiveData.asStateFlow() init { viewModelScope.launch { @@ -26,6 +31,6 @@ class CatsViewModel( class CatsViewModelFactory(private val catsRepository: CatsRepository) : ViewModelProvider.NewInstanceFactory() { - override fun create(modelClass: Class): T = + override fun create(modelClass: Class): T = CatsViewModel(catsRepository) as T } \ 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..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 diff --git a/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt b/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt index edea434b..e3020f7c 100644 --- a/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt +++ b/flowcats/src/main/java/otus/homework/flowcats/MainActivity.kt @@ -1,21 +1,42 @@ package otus.homework.flowcats -import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import android.widget.ProgressBar +import android.widget.Toast import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.isVisible +import androidx.lifecycle.lifecycleScope +import kotlinx.coroutines.InternalCoroutinesApi +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.launch class MainActivity : AppCompatActivity() { private val diContainer = DiContainer() private val catsViewModel by viewModels { CatsViewModelFactory(diContainer.repository) } + @OptIn(InternalCoroutinesApi::class) 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) + lifecycleScope.launch { + catsViewModel.catsLiveData.collect { + view.findViewById(R.id.progressBar).isVisible = it is Result.Loading + when (it) { + is Result.Success -> { + view.populate(it.fact) + } + + is Result.Error -> { + Toast.makeText(this@MainActivity, it.message, Toast.LENGTH_LONG).show() + } + + else -> {} + } + } } } } \ 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..631e24b0 --- /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 Error(val message: String) : Result() + data class Success(val fact: Fact) : Result() + object Loading : Result() +} \ No newline at end of file diff --git a/flowcats/src/main/res/layout/activity_main.xml b/flowcats/src/main/res/layout/activity_main.xml index dbcedd2f..bc1f4c66 100644 --- a/flowcats/src/main/res/layout/activity_main.xml +++ b/flowcats/src/main/res/layout/activity_main.xml @@ -18,4 +18,15 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + \ 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..4f53d0d2 100644 --- a/operators/src/main/java/otus/homework/flow/SampleInteractor.kt +++ b/operators/src/main/java/otus/homework/flow/SampleInteractor.kt @@ -1,7 +1,15 @@ package otus.homework.flow import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onCompletion +import kotlinx.coroutines.flow.take +import kotlinx.coroutines.flow.zip @ExperimentalCoroutinesApi class SampleInteractor( @@ -18,7 +26,13 @@ class SampleInteractor( * 6) возвращает результат */ fun task1(): Flow { - return flowOf() + val flow = sampleRepository.produceNumbers() + .map { it * 5 } + .filter { it > 20 } + .filter { it % 2 == 1 } + .map { number -> "$number won" } + .take(3) + return flow } /** @@ -28,8 +42,15 @@ class SampleInteractor( * Если входное число делится на 15 - эмитим само число и после него эмитим строку FizzBuzz * Если число не делится на 3,5,15 - эмитим само число */ - fun task2(): Flow { - return flowOf() + fun task2(): Flow = flow { + sampleRepository.produceNumbers().collect { number -> + emit("$number") + when { + number % 15 == 0 -> emit("FizzBuzz") + number % 5 == 0 -> emit("Buzz") + number % 3 == 0 -> emit("Fizz") + } + } } /** @@ -38,7 +59,12 @@ class SampleInteractor( * Если айтемы в одно из флоу кончились то результирующий флоу также должен закончится */ fun task3(): Flow> { - return flowOf() + val colors = sampleRepository.produceColors() + val forms = sampleRepository.produceForms() + val zipped = colors.zip(forms) { color, form -> + Pair(color, form) + } + return zipped } /** @@ -47,7 +73,14 @@ class SampleInteractor( * Если тип эксепшена != IllegalArgumentException, пробросьте его дальше * При любом исходе, будь то выброс исключения или успешная отработка функции вызовите метод dotsRepository.completed() */ - fun task4(): Flow { - return flowOf() + fun task4(): Flow = flow { + sampleRepository.produceNumbers().collect { number -> + emit(number) + } + }.onCompletion { + sampleRepository.completed() + }.catch { error -> + if (error is IllegalArgumentException) emit(-1) + else throw error } } \ No newline at end of file diff --git a/operators/src/main/java/otus/homework/flow/SampleRepository.kt b/operators/src/main/java/otus/homework/flow/SampleRepository.kt index a16726e6..24113124 100644 --- a/operators/src/main/java/otus/homework/flow/SampleRepository.kt +++ b/operators/src/main/java/otus/homework/flow/SampleRepository.kt @@ -1,14 +1,17 @@ package otus.homework.flow import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf interface SampleRepository { - fun produceNumbers(): Flow + fun produceNumbers(): Flow = flowOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) - fun produceColors(): Flow + fun produceColors(): Flow = + flowOf("Red", "Orange", "Yellow", "Green", "Blue", "Violet", "Black", "White", "Gray") - fun produceForms(): Flow + fun produceForms(): Flow = + flowOf("Triangle", "Circle", "Square", "Rectangle", "Oval", "Rhombus") fun completed() } \ No newline at end of file