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
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.4.0"
}
55 changes: 55 additions & 0 deletions app/src/main/java/otus/homework/coroutines/CatViewViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package otus.homework.coroutines

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.*
import java.net.SocketTimeoutException

class CatViewViewModel(
private val catsService: CatsService,
private val photoService: PhotoService,
) : ViewModel() {

private val _catsLiveData = MutableLiveData<Result>()
val catsLiveData: LiveData<Result> = _catsLiveData
private val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
CrashMonitor.trackWarning()
_catsLiveData.value =
Error(
if (throwable is SocketTimeoutException) TIME_OUT
else throwable.message ?: throwable.toString()
)
}

init {
onInitComplete()
}

fun onInitComplete() {
viewModelScope.launch(exceptionHandler) {
coroutineScope {
val fact = async(Dispatchers.IO) {
catsService.getCatFact()
}
val photo = async(Dispatchers.IO) {
photoService.getPhoto()
}
val factWithPhoto = FactWithPhoto(
fact = fact.await(),
photo = photo.await().first().url
)
_catsLiveData.value = Success(factWithPhoto)
}
}
}

companion object {
const val TIME_OUT = "Не удалось получить ответ от сервера"
}
}

sealed class Result
data class Success(val fact: FactWithPhoto) : Result()
data class Error(val message: String) : Result()
35 changes: 0 additions & 35 deletions app/src/main/java/otus/homework/coroutines/CatsPresenter.kt

This file was deleted.

3 changes: 1 addition & 2 deletions app/src/main/java/otus/homework/coroutines/CatsService.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package otus.homework.coroutines

import retrofit2.Call
import retrofit2.http.GET

interface CatsService {

@GET("fact")
fun getCatFact() : Call<Fact>
suspend fun getCatFact(): Fact
}
20 changes: 8 additions & 12 deletions app/src/main/java/otus/homework/coroutines/CatsView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,27 @@ 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

override fun onFinishInflate() {
super.onFinishInflate()
findViewById<Button>(R.id.button).setOnClickListener {
presenter?.onInitComplete()
}
override fun populate(factWithPhoto: FactWithPhoto) {
findViewById<TextView>(R.id.fact_textView).text = factWithPhoto.fact.fact
Picasso.get()
.load(factWithPhoto.photo)
.into(findViewById<ImageView>(R.id.image))
}

override fun populate(fact: Fact) {
findViewById<TextView>(R.id.fact_textView).text = fact.fact
}
}

interface ICatsView {
fun populate(factWithPhoto: FactWithPhoto)

fun populate(fact: Fact)
}
9 changes: 9 additions & 0 deletions app/src/main/java/otus/homework/coroutines/DiContainer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,14 @@ class DiContainer {
.build()
}

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

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

val photoService by lazy { retrofitPhoto.create(PhotoService::class.java) }
}
8 changes: 4 additions & 4 deletions app/src/main/java/otus/homework/coroutines/Fact.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package otus.homework.coroutines
import com.google.gson.annotations.SerializedName

data class Fact(
@field:SerializedName("fact")
val fact: String,
@field:SerializedName("length")
val length: Int
@field:SerializedName("fact")
val fact: String,
@field:SerializedName("length")
val length: Int
)
6 changes: 6 additions & 0 deletions app/src/main/java/otus/homework/coroutines/FactWithPhoto.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package otus.homework.coroutines

data class FactWithPhoto(
val fact: Fact,
val photo: String
)
35 changes: 22 additions & 13 deletions app/src/main/java/otus/homework/coroutines/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,30 +1,39 @@
package otus.homework.coroutines

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider

class MainActivity : AppCompatActivity() {

lateinit var catsPresenter: CatsPresenter

private val diContainer = DiContainer()


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

val viewModelFactory =
ViewModelFactory(diContainer.service, diContainer.photoService)
val catsViewModel = ViewModelProvider(this, factory = viewModelFactory)[CatViewViewModel::class.java]

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.getViewById(R.id.button).setOnClickListener {
catsViewModel.onInitComplete()
}
super.onStop()
catsViewModel.catsLiveData.observe(this, Observer { result ->
when (result) {
is Error -> {
Toast.makeText(this, result.message, Toast.LENGTH_LONG).show()
}

is Success -> {
view.populate(result.fact)
}
}
})
}
}
14 changes: 14 additions & 0 deletions app/src/main/java/otus/homework/coroutines/Photo.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 Photo(
@field:SerializedName("id")
val id: String,
@field:SerializedName("url")
val url: String,
@field:SerializedName("width")
val width: Int,
@field:SerializedName("height")
val height: Int,
)
9 changes: 9 additions & 0 deletions app/src/main/java/otus/homework/coroutines/PhotoService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package otus.homework.coroutines

import retrofit2.http.GET

interface PhotoService {

@GET("search")
suspend fun getPhoto(): List<Photo>
}
16 changes: 16 additions & 0 deletions app/src/main/java/otus/homework/coroutines/ViewModelFactory.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package otus.homework.coroutines

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

class ViewModelFactory(
private val catsService: CatsService,
private val photoService: PhotoService,
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(CatViewViewModel::class.java)) {
return CatViewViewModel(catsService, photoService) as T
}
error("Unknown ViewModel class")
}
}
55 changes: 33 additions & 22 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
@@ -1,30 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<otus.homework.coroutines.CatsView xmlns:android="http://schemas.android.com/apk/res/android"
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"
tools:context=".MainActivity">
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"
tools:context=".MainActivity">

<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="cats"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@+id/fact_textView"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="@+id/fact_textView"
android:textColor="@color/black"
android:textSize="24sp"
android:layout_width="wrap_content"
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" />
android:id="@+id/fact_textView"
android:textColor="@color/black"
android:textSize="24sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/image"/>

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/more_facts"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/fact_textView" />
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/more_facts"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/fact_textView"/>

</otus.homework.coroutines.CatsView>
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package otus.homework.coroutines

import org.junit.Test

import org.junit.Assert.*
import org.junit.Test

/**
* Example local unit test, which will execute on the development machine (host).
Expand Down