Skip to content

Homework #206

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: development
Choose a base branch
from
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
7 changes: 5 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,12 @@ dependencies {
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.google.code.gson:gson:2.10'
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.squareup.picasso:picasso:2.71828'
}
implementation "com.squareup.okhttp3:logging-interceptor:4.11.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0"
implementation 'androidx.activity:activity-ktx:1.8.2'
}
47 changes: 31 additions & 16 deletions app/src/main/java/otus/homework/coroutines/CatsPresenter.kt
Original file line number Diff line number Diff line change
@@ -1,35 +1,50 @@
package otus.homework.coroutines

import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import java.net.SocketTimeoutException

class CatsPresenter(
private val catsService: CatsService
private val catsService: CatsService,
private val imageCatService: ImageCatService
) {

private var _catsView: ICatsView? = null
private var error = false

fun onInitComplete() {
catsService.getCatFact().enqueue(object : Callback<Fact> {

override fun onResponse(call: Call<Fact>, response: Response<Fact>) {
if (response.isSuccessful && response.body() != null) {
_catsView?.populate(response.body()!!)
}
}
private val presenterScope = CoroutineScope(Dispatchers.Main.immediate)

override fun onFailure(call: Call<Fact>, t: Throwable) {
fun onInitComplete() {
val fact = presenterScope.async { catsService.getCatFact() }
val image = presenterScope.async { imageCatService.getCatImage() }
presenterScope.launch {
try {
val responseFact = fact.await()
val responseImage = image.await()
if (responseFact.isSuccessful && responseFact.body() != null
&& responseImage.isSuccessful && responseImage.body() != null) {
error = false
_catsView?.populate(ModelPresentation(responseFact.body()!!, responseImage.body()!!.first()))
} else {error = true}
} catch (s: SocketTimeoutException) {
error = true
} catch (e: Exception) {
error = true
CrashMonitor.trackWarning()
}
})
}
}

}

fun attachView(catsView: ICatsView) {
_catsView = catsView
}

fun detachView() {
_catsView = null
presenterScope.cancel()
}
}
}
5 changes: 3 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,11 @@
package otus.homework.coroutines

import retrofit2.Call
import retrofit2.Response
import retrofit2.http.GET

interface CatsService {

@GET("fact")
fun getCatFact() : Call<Fact>
}
suspend fun getCatFact() : Response<Fact>
}
16 changes: 11 additions & 5 deletions app/src/main/java/otus/homework/coroutines/CatsView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ 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 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
var presenter :CatsViewModel? = null

override fun onFinishInflate() {
super.onFinishInflate()
Expand All @@ -21,12 +23,16 @@ class CatsView @JvmOverloads constructor(
}
}

override fun populate(fact: Fact) {
findViewById<TextView>(R.id.fact_textView).text = fact.fact
override fun populate(data: ModelPresentation) {
findViewById<TextView>(R.id.fact_textView).text = data.fact.fact
val im = findViewById<ImageView>(R.id.image)
Picasso.get()
.load(data.imageCat.url)
.into(im)
}
}

interface ICatsView {

fun populate(fact: Fact)
}
fun populate(data: ModelPresentation)
}
65 changes: 65 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,65 @@
package otus.homework.coroutines

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

class CatsViewModel(
private val catsService: CatsService,
private val imageCatService: ImageCatService
) : ViewModel() {

private val _catsModel = MutableLiveData<Result>()
val catsModel: LiveData<Result> = _catsModel

private val handler = CoroutineExceptionHandler { coroutineContext, throwable ->
if (throwable is SocketTimeoutException) _catsModel.value = Error
else CrashMonitor.trackWarning()
}
init {
onInitComplete()
}

fun onInitComplete() {
viewModelScope.launch(handler + CoroutineName("CatsCoroutine")) {
val fact = async { catsService.getCatFact() }
val image = async { imageCatService.getCatImage() }

val responseFact = fact.await()
val responseImage = image.await()
if (responseFact.isSuccessful && responseFact.body() != null
&& responseImage.isSuccessful && responseImage.body() != null
) {
_catsModel.value = Success(
ModelPresentation(
responseFact.body()!!,
responseImage.body()!!.first()
)
)
}
}
}

}


class CatsViewModelFactory(
private val catsService: CatsService,
private val imageCatService: ImageCatService
) :
ViewModelProvider.NewInstanceFactory() {

override fun <T : ViewModel> create(modelClass: Class<T>): T =
CatsViewModel(catsService, imageCatService) as T
}

sealed class Result
data class Success(val data: ModelPresentation) : Result()
object Error : Result()
11 changes: 10 additions & 1 deletion app/src/main/java/otus/homework/coroutines/DiContainer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,13 @@ class DiContainer {
}

val service by lazy { retrofit.create(CatsService::class.java) }
}

private val retrofit2 by lazy {
Retrofit.Builder()
.baseUrl("https://api.thecatapi.com/v1/images/")
.addConverterFactory(GsonConverterFactory.create())
.build()
}

val service2 by lazy { retrofit2.create(ImageCatService::class.java) }
}
14 changes: 14 additions & 0 deletions app/src/main/java/otus/homework/coroutines/ImageCat.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package otus.homework.coroutines

import com.google.gson.annotations.SerializedName

data class ImageCat(
@field:SerializedName("id")
val id: String,
@field:SerializedName("url")
val url: String,
@field:SerializedName("width")
val width: Int,
@field:SerializedName("height")
val height: Int
)
10 changes: 10 additions & 0 deletions app/src/main/java/otus/homework/coroutines/ImageCatService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package otus.homework.coroutines

import retrofit2.Response
import retrofit2.http.GET

interface ImageCatService {

@GET("search")
suspend fun getCatImage() : Response<List<ImageCat>>
}
35 changes: 21 additions & 14 deletions app/src/main/java/otus/homework/coroutines/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,30 +1,37 @@
package otus.homework.coroutines

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

lateinit var catsPresenter: CatsPresenter

private val diContainer = DiContainer()
private val catsViewModel by viewModels<CatsViewModel> {
CatsViewModelFactory(
diContainer.service,
diContainer.service2
)
}

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

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

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

override fun onStop() {
if (isFinishing) {
catsPresenter.detachView()
view.presenter = catsViewModel

catsViewModel.catsModel.observe(this) { result ->
when (result) {
is Success -> view.populate(result.data)
Error -> Toast.makeText(
this,
"Не удалось получить ответ от сервером",
Toast.LENGTH_LONG
).show()
}
}
super.onStop()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package otus.homework.coroutines

data class ModelPresentation(
val fact: Fact,
val imageCat: ImageCat
)
10 changes: 9 additions & 1 deletion app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,12 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/fact_textView" />

</otus.homework.coroutines.CatsView>
<ImageView
android:id="@+id/image"
android:layout_width="150dp"
android:layout_height="150dp"
app:layout_constraintTop_toBottomOf="@id/button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>

</otus.homework.coroutines.CatsView>
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ buildscript {
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.2.1'
classpath 'com.android.tools.build:gradle:8.1.4'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

// NOTE: Do not place your application dependencies here; they belong
Expand All @@ -23,4 +23,4 @@ allprojects {

task clean(type: Delete) {
delete rootProject.buildDir
}
}