Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ dependencies {
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.0"
}
6 changes: 6 additions & 0 deletions app/src/main/java/otus/homework/coroutines/CatFact.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package otus.homework.coroutines

data class CatFact(
val fact: Fact,
val imageUrl: String = "",
)
59 changes: 49 additions & 10 deletions app/src/main/java/otus/homework/coroutines/CatsPresenter.kt
Original file line number Diff line number Diff line change
@@ -1,28 +1,66 @@
package otus.homework.coroutines

import android.content.res.Resources
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.net.SocketTimeoutException

class CatsPresenter(
private val catsService: CatsService
private val catsService: CatsService,
private val resources: Resources,
) {

private var _catsView: ICatsView? = null

fun onInitComplete() {
catsService.getCatFact().enqueue(object : Callback<Fact> {
private val presenterScope = CoroutineScope(Dispatchers.Main + CoroutineName("CatsCoroutine"))
private var job: Job = Job()

fun load() {
job = presenterScope.launch {
runCatching {
val facts = catsService.getCatFact()
val imageUrl = catsService.loadImage().first().url

override fun onResponse(call: Call<Fact>, response: Response<Fact>) {
if (response.isSuccessful && response.body() != null) {
_catsView?.populate(response.body()!!)
}
CatFact(
fact = facts,
imageUrl = imageUrl,
)
}.onFailure {
errorHandler(it)
Comment thread
BambinoGrandi marked this conversation as resolved.
Outdated
}.onSuccess {
_catsView?.populate(it)
}
}
}

override fun onFailure(call: Call<Fact>, t: Throwable) {
CrashMonitor.trackWarning()
fun onInitComplete() {
job = presenterScope.launch {
try {
val facts = catsService.getCatFact()
_catsView?.populate(CatFact(facts))
} catch (e: Exception) {
errorHandler(e)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

вот тут еще остался перехват CancellationException

}
})
}
}

private fun errorHandler(e: Throwable) {
if (e is SocketTimeoutException) {
_catsView?.showToast(
resources.getString(
R.string.socet_timeout_error,
),
)
} else {
CrashMonitor.trackWarning()
_catsView?.showToast(e.message.orEmpty())
}
}

fun attachView(catsView: ICatsView) {
Expand All @@ -31,5 +69,6 @@ class CatsPresenter(

fun detachView() {
_catsView = null
job.cancel()
}
}
6 changes: 4 additions & 2 deletions app/src/main/java/otus/homework/coroutines/CatsService.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package otus.homework.coroutines

import retrofit2.Call
import retrofit2.http.GET

interface CatsService {

@GET("fact")
fun getCatFact() : Call<Fact>
suspend fun getCatFact() : Fact

@GET("https://api.thecatapi.com/v1/images/search")
suspend fun loadImage() : List<FactImage>
}
21 changes: 17 additions & 4 deletions app/src/main/java/otus/homework/coroutines/CatsView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ package otus.homework.coroutines
import android.content.Context
import android.util.AttributeSet
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.constraintlayout.widget.ConstraintLayout
import com.squareup.picasso.Picasso

class CatsView @JvmOverloads constructor(
context: Context,
Expand All @@ -17,16 +20,26 @@ class CatsView @JvmOverloads constructor(
override fun onFinishInflate() {
super.onFinishInflate()
findViewById<Button>(R.id.button).setOnClickListener {
presenter?.onInitComplete()
presenter?.load()
}
}

override fun populate(fact: Fact) {
findViewById<TextView>(R.id.fact_textView).text = fact.fact
override fun populate(fact: CatFact) {
findViewById<TextView>(R.id.fact_textView).text = fact.fact.fact
val imageView = findViewById<ImageView>(R.id.fact_image)
Picasso
.get()
.load(fact.imageUrl)
.into(imageView)
}

override fun showToast(message: String) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
}

interface ICatsView {

fun populate(fact: Fact)
fun populate(fact: CatFact)
fun showToast(message: String)
}
64 changes: 64 additions & 0 deletions app/src/main/java/otus/homework/coroutines/CatsViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package otus.homework.coroutines

import android.content.res.Resources
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import java.net.SocketTimeoutException

class CatsViewModel(
private val catsService: CatsService,
private val resources: Resources,
) : ViewModel() {

private val _catsFact = MutableStateFlow<Result>(Result.Success(Unit))
val catsFact = _catsFact.asStateFlow()

private val exceptionHandler = CoroutineExceptionHandler { _, _ ->
CrashMonitor.trackWarning()
}

fun load() {
viewModelScope.launch(exceptionHandler) {
runCatching {
val facts = catsService.getCatFact()
val imageUrl = catsService.loadImage().first().url

CatFact(
fact = facts,
imageUrl = imageUrl,
)
}.onFailure { error ->
_catsFact.update {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

также перехват CancellationException

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

исправил

Result.Error(errorHandler(error))
}
}.onSuccess { fact ->
_catsFact.update {
Result.Success(fact)
}
}
}
}

private fun errorHandler(e: Throwable): String {
Log.d("Fact", e.message.toString())
return if (e is SocketTimeoutException) {
resources.getString(
R.string.socet_timeout_error,
)
} else {
e.message.orEmpty()
}
}
}


sealed interface Result {
data class Success<T>(val result: T) : Result
data class Error(val message: String) : Result
}
8 changes: 8 additions & 0 deletions app/src/main/java/otus/homework/coroutines/FactImage.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package otus.homework.coroutines

import com.google.gson.annotations.SerializedName

data class FactImage(
@field:SerializedName("url")
val url: String,
)
4 changes: 2 additions & 2 deletions app/src/main/java/otus/homework/coroutines/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ class MainActivity : AppCompatActivity() {
val view = layoutInflater.inflate(R.layout.activity_main, null) as CatsView
setContentView(view)

catsPresenter = CatsPresenter(diContainer.service)
catsPresenter = CatsPresenter(diContainer.service, resources)
view.presenter = catsPresenter
catsPresenter.attachView(view)
catsPresenter.onInitComplete()
catsPresenter.load()
}

override fun onStop() {
Expand Down
19 changes: 15 additions & 4 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,31 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:padding="16dp"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">

<ImageView
android:id="@+id/fact_image"
android:layout_width="match_parent"
android:layout_height="260dp"
android:contentDescription="@null"
android:scaleType="centerCrop"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/fact_textView"/>

<TextView
android:id="@+id/fact_textView"
android:textColor="@color/black"
android:textSize="24sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toBottomOf="@id/fact_image" />

<Button
android:id="@+id/button"
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<resources>
<string name="app_name">Cat Facts </string>
<string name="more_facts">More Facts</string>
<string name="refresh_screen">Refresh Screen</string>
<string name="socet_timeout_error">Не удалось получить ответ от сервером</string>
</resources>