Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,8 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0"
implementation 'androidx.activity:activity-ktx:1.9.0'
implementation 'com.squareup.picasso:picasso:2.71828'
}
17 changes: 17 additions & 0 deletions app/src/main/java/otus/homework/coroutines/CatImage.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package otus.homework.coroutines

import com.google.gson.annotations.SerializedName

data class CatImage(
@field:SerializedName("id")
val id: String,

@field:SerializedName("url")
val url: String,

@field:SerializedName("width")
val width: Int,

@field:SerializedName("height")
val height: Int
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package otus.homework.coroutines

data class CatPresentationModel(
val fact: String,
val imageUrl: String
)
35 changes: 0 additions & 35 deletions app/src/main/java/otus/homework/coroutines/CatsPresenter.kt

This file was deleted.

7 changes: 5 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,13 @@
package otus.homework.coroutines

import retrofit2.Call
import retrofit2.http.GET

interface CatsService {

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

@GET("v1/images/search")
suspend fun getCatImage(): List<CatImage>

}
28 changes: 21 additions & 7 deletions app/src/main/java/otus/homework/coroutines/CatsView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,44 @@ 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,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), ICatsView {

var presenter :CatsPresenter? = null
lateinit var factTextView: TextView
lateinit var catImageView: ImageView
lateinit var button: Button

override fun onFinishInflate() {
super.onFinishInflate()
findViewById<Button>(R.id.button).setOnClickListener {
presenter?.onInitComplete()
}

factTextView = findViewById(R.id.fact_textView)
catImageView = findViewById(R.id.cat_imageView)
button = findViewById(R.id.button)
}

override fun populate(data: CatPresentationModel) {
factTextView.text = data.fact
Picasso.get()
.load(data.imageUrl)
.into(catImageView)
}

override fun populate(fact: Fact) {
findViewById<TextView>(R.id.fact_textView).text = fact.fact
override fun showToast(message: String) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
}

interface ICatsView {

fun populate(fact: Fact)
fun populate(data: CatPresentationModel)
fun showToast(message: String)
}
52 changes: 52 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,52 @@
package otus.homework.coroutines

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import java.net.SocketTimeoutException

class CatsViewModel(
private val catsService: CatsService
) : ViewModel() {

private val _catsState = MutableLiveData<Result<CatPresentationModel>?>()
val catsState: LiveData<Result<CatPresentationModel>?> = _catsState

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

val errorMessage = when (throwable) {
is SocketTimeoutException -> "Не удалось получить ответ от сервера"
else -> throwable.message ?: "Произошла ошибка"
}

_catsState.postValue(Result.Error(errorMessage, throwable))
}

fun onInitComplete() {
viewModelScope.launch(exceptionHandler) {
_catsState.postValue(null)

val factDeferred = async(Dispatchers.IO) {
catsService.getCatFact()
}
val imageDeferred = async(Dispatchers.IO) {
catsService.getCatImage().first()
}
val fact = factDeferred.await()
val image = imageDeferred.await()

val model = CatPresentationModel(
fact = fact.fact,
imageUrl = image.url
)
_catsState.postValue(Result.Success(model))
}
}

}
18 changes: 18 additions & 0 deletions app/src/main/java/otus/homework/coroutines/CatsViewModelFactory.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package otus.homework.coroutines

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider

class CatsViewModelFactory(
private val catsService: CatsService
) : ViewModelProvider.Factory {

@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(CatsViewModel::class.java)) {
return CatsViewModel(catsService) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}

}
3 changes: 2 additions & 1 deletion app/src/main/java/otus/homework/coroutines/CrashMonitor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ object CrashMonitor {
/**
* Pretend this is Crashlytics/AppCenter
*/
fun trackWarning() {
fun trackWarning(throwable: Throwable? = null) {
throwable?.printStackTrace()
}
}
24 changes: 22 additions & 2 deletions app/src/main/java/otus/homework/coroutines/DiContainer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,32 @@ import retrofit2.converter.gson.GsonConverterFactory

class DiContainer {

private val retrofit by lazy {
private val catFactRetrofit by lazy {
Retrofit.Builder()
.baseUrl("https://catfact.ninja/")
.addConverterFactory(GsonConverterFactory.create())
.build()
}

val service by lazy { retrofit.create(CatsService::class.java) }
private val catImageRetrofit by lazy {
Retrofit.Builder()
.baseUrl("https://api.thecatapi.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
}

val service by lazy {
object : CatsService {
private val catFactService = catFactRetrofit.create(CatsService::class.java)
private val catImageService = catImageRetrofit.create(CatsService::class.java)

override suspend fun getCatFact(): Fact {
return catFactService.getCatFact()
}

override suspend fun getCatImage(): List<CatImage> {
return catImageService.getCatImage()
}
}
}
}
40 changes: 27 additions & 13 deletions app/src/main/java/otus/homework/coroutines/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,43 @@ package otus.homework.coroutines

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.activity.viewModels
import androidx.lifecycle.Observer

class MainActivity : AppCompatActivity() {

lateinit var catsPresenter: CatsPresenter

private val diContainer = DiContainer()
private val viewModel: CatsViewModel by viewModels {
CatsViewModelFactory(diContainer.service)
}

private lateinit var catsView: CatsView

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

val view = layoutInflater.inflate(R.layout.activity_main, null) as CatsView
setContentView(view)
catsView = layoutInflater.inflate(R.layout.activity_main, null) as CatsView
setContentView(catsView)

catsPresenter = CatsPresenter(diContainer.service)
view.presenter = catsPresenter
catsPresenter.attachView(view)
catsPresenter.onInitComplete()
}
catsView.button.setOnClickListener {
viewModel.onInitComplete()
}

override fun onStop() {
if (isFinishing) {
catsPresenter.detachView()
viewModel.catsState.observe(this, Observer { result ->
when (result) {
is Result.Success -> {
catsView.populate(result.data)
}
is Result.Error -> {
catsView.showToast(result.message)
}
else -> {}
}
})

if (savedInstanceState == null) {
viewModel.onInitComplete()
}
super.onStop()
}

}
6 changes: 6 additions & 0 deletions app/src/main/java/otus/homework/coroutines/Result.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package otus.homework.coroutines

sealed class Result<out T> {
data class Success<out T>(val data: T) : Result<T>()
data class Error(val message: String, val throwable: Throwable? = null) : Result<Nothing>()
}
16 changes: 13 additions & 3 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,26 @@
android:layout_height="match_parent"
tools:context=".MainActivity">

<ImageView
android:id="@+id/cat_imageView"
android:layout_width="200dp"
android:layout_height="200dp"
android:scaleType="centerCrop"
android:contentDescription="@string/cat_image_description"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="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_width="0dp"
android:layout_height="wrap_content"
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/cat_imageView" />

<Button
android:id="@+id/button"
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<resources>
<string name="app_name">Cat Facts </string>
<string name="more_facts">More Facts</string>
<string name="cat_image_description">Cat Image</string>
</resources>