Skip to content

Coroutines homework #247

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
2 changes: 2 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,6 @@ 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.activity:activity-ktx:1.9.2'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6'
}
35 changes: 0 additions & 35 deletions app/src/main/java/otus/homework/coroutines/CatsPresenter.kt

This file was deleted.

8 changes: 7 additions & 1 deletion app/src/main/java/otus/homework/coroutines/CatsService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,11 @@ import retrofit2.http.GET
interface CatsService {

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

interface CatsImageService {

@GET("search")
suspend fun getCatImage(): List<Image>
}
36 changes: 30 additions & 6 deletions app/src/main/java/otus/homework/coroutines/CatsView.kt
Original file line number Diff line number Diff line change
@@ -1,32 +1,56 @@
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.google.gson.annotations.SerializedName
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 catsViewModel: CatsViewModel? = null

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

override fun populate(fact: Fact) {
findViewById<TextView>(R.id.fact_textView).text = fact.fact
override fun populate(catsData: CatsData) {
findViewById<TextView>(R.id.fact_textView).text = catsData.fact
Picasso.get().load(catsData.image.url).into(findViewById<ImageView>(R.id.cat_imageView))
}

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

}
}

interface ICatsView {

fun populate(fact: Fact)
}
fun populate(catsData: CatsData)
fun showError(message: String)
}


data class Image(
@field:SerializedName("url")
val url: String
)

data class CatsData(
val fact: String,
val image: Image
)
55 changes: 55 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,55 @@
package otus.homework.coroutines

import android.app.Application
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.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch

class CatsViewModel(
private val catsService: CatsService,
private val imageService: CatsImageService,
private val context: Application
) : ViewModel() {
private val _catsLiveData = MutableLiveData<Result>()
val catsLiveData: LiveData<Result> = _catsLiveData

init {
getData()
}

fun getData() {
val handler = CoroutineExceptionHandler { _, throwable ->
CrashMonitor.trackWarning()
if (throwable is java.net.SocketTimeoutException) _catsLiveData.value =
Error(context.getString(R.string.socket_timeout_exception))
else _catsLiveData.value =
Error(throwable.message ?: context.getString(R.string.unknown_exception))
}
viewModelScope.launch(handler) {
coroutineScope {
val fact = async { catsService.getCatFact().fact }
val image = async { imageService.getCatImage().first() }
_catsLiveData.value = Success(CatsData(fact.await(), image.await()))
}
}
}
}

class CatsViewModelFactory(
private val catsService: CatsService,
private val imageService: CatsImageService,
private val context: Application
) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T =
CatsViewModel(catsService, imageService, context) as T
}

sealed class Result
data class Success(val data: CatsData) : Result()
data class Error(val message: String) : Result()
14 changes: 10 additions & 4 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,18 @@ import retrofit2.converter.gson.GsonConverterFactory

class DiContainer {

private val retrofit by lazy {
private fun getRetrofit(url: String) =
Retrofit.Builder()
.baseUrl("https://catfact.ninja/")
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build()
}

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

val service: CatsService by lazy { getRetrofit(FACT_URL).create(CatsService::class.java) }
val imageService: CatsImageService by lazy { getRetrofit(IMAGE_URL).create(CatsImageService::class.java) }

companion object {
private const val FACT_URL = "https://catfact.ninja/"
private const val IMAGE_URL = "https://api.thecatapi.com/v1/images/"
}
}
25 changes: 14 additions & 11 deletions app/src/main/java/otus/homework/coroutines/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@ package otus.homework.coroutines

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

class MainActivity : AppCompatActivity() {

lateinit var catsPresenter: CatsPresenter
private val catsViewModel by viewModels<CatsViewModel> {
CatsViewModelFactory(
diContainer.service,
diContainer.imageService,
application
)
}

private val diContainer = DiContainer()

Expand All @@ -15,16 +22,12 @@ class MainActivity : AppCompatActivity() {
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.catsViewModel = catsViewModel
catsViewModel.catsLiveData.observe(this) {
when (it) {
is Error -> view.showError(it.message)
is Success -> view.populate(it.data)
}
}
super.onStop()
}
}
9 changes: 9 additions & 0 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@
android:layout_height="match_parent"
tools:context=".MainActivity">

<ImageView
android:id="@+id/cat_imageView"
android:layout_width="match_parent"
android:layout_height="200dp"
android:contentDescription="Cat's image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/fact_textView"
android:textColor="@color/black"
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="socket_timeout_exception">socket timeout</string>
<string name="unknown_exception">unknown error</string>
</resources>