Skip to content

Homework done #2

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 5 commits 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 @@ -42,4 +42,6 @@ dependencies {
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
}
8 changes: 8 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,8 @@
package otus.homework.coroutines

import com.google.gson.annotations.SerializedName

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

data class CatsModel(
val fact: Fact,
val image: CatImage
)
37 changes: 24 additions & 13 deletions app/src/main/java/otus/homework/coroutines/CatsPresenter.kt
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
package otus.homework.coroutines

import retrofit2.Call
import retrofit2.Callback
import kotlinx.coroutines.*
import retrofit2.Response
import java.lang.Exception
import java.net.SocketTimeoutException

class CatsPresenter(
private val catsService: CatsService
private val catsService: CatsService,
private val imageService: ImageService
) {

private var _catsView: ICatsView? = null
private var catsScope = PresenterScope()

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()!!)
catsScope.launch {
try {
val fact = async { handleResponse(catsService.getCatFact())
}
val image = async { handleResponse(imageService.getRandomImage()) }
Copy link

Choose a reason for hiding this comment

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

val fact = catsScope.async { handleResponse(catsService.getCatFact())  }
val image = catsScope.async { handleResponse(imageService.getRandomImage()) }

иначе при отсутствии интернета будет креш

_catsView?.populate(CatsModel(fact.await(), image.await()))
} catch (ex: Exception) {
when (ex) {
is SocketTimeoutException -> _catsView?.showNoResponseToast()
else -> {
_catsView?.showToast(ex.message ?: "Error")
CrashMonitor.trackWarning()
}
}
}

override fun onFailure(call: Call<Fact>, t: Throwable) {
CrashMonitor.trackWarning()
}
})
}
}

fun attachView(catsView: ICatsView) {
Expand All @@ -32,4 +39,8 @@ class CatsPresenter(
fun detachView() {
_catsView = null
}

fun cancelCatsJob() {
catsScope.cancel()
}
}
3 changes: 2 additions & 1 deletion 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("random?animal_type=cat")
fun getCatFact() : Call<Fact>
suspend fun getCatFact() : Response<Fact>
}
25 changes: 21 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 @@ -21,12 +24,26 @@ class CatsView @JvmOverloads constructor(
}
}

override fun populate(fact: Fact) {
findViewById<TextView>(R.id.fact_textView).text = fact.text
override fun populate(model: CatsModel) {
findViewById<TextView>(R.id.fact_textView).text = model.fact.text
Picasso.get()
.load(model.image.fileUrl)
.fit()
.centerInside()
.into(findViewById<ImageView>(R.id.imageView))
}

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

override fun showNoResponseToast() {
showToast(context.getString(R.string.no_server_response))
}
}

interface ICatsView {

fun populate(fact: Fact)
fun populate(model: CatsModel)
fun showToast(message: String)
fun showNoResponseToast()
}
51 changes: 51 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,51 @@
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.async
import kotlinx.coroutines.launch
import java.lang.Exception
import java.net.SocketTimeoutException

sealed class Result

class Success<T>(val data: T) : Result()
class Error(val errorMsg: String) : Result()

class CatsViewModel(
private val catsService: CatsService,
private val imageService: ImageService
) : ViewModel() {

private val catInfo: MutableLiveData<Result> = MutableLiveData<Result>()
private val exceptionHandler = CoroutineExceptionHandler() { _, exception ->
when(exception){
is SocketTimeoutException -> catInfo.value = Error(exception.localizedMessage ?: "An error occurred")
else -> CrashMonitor.trackWarning()
}
}

init {
loadInfo()
}

fun getCatInfo(): LiveData<Result> {
return catInfo
}

private fun loadInfo() {
viewModelScope.launch(exceptionHandler) {
val fact = async { handleResponse(catsService.getCatFact()) }
val image = async { handleResponse(imageService.getRandomImage()) }
catInfo.value = Success<CatsModel>(CatsModel(fact.await(), image.await()))
}
}

fun onButtonClicked() {
loadInfo()
}

}
8 changes: 8 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,13 @@ class DiContainer {
.build()
}

private val imageRetrofit by lazy {
Retrofit.Builder()
.baseUrl("https://aws.random.cat/")
.addConverterFactory(GsonConverterFactory.create())
.build()
}

val service by lazy { retrofit.create(CatsService::class.java) }
val imageService by lazy { imageRetrofit.create(ImageService::class.java) }
}
16 changes: 16 additions & 0 deletions app/src/main/java/otus/homework/coroutines/ImageService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package otus.homework.coroutines

import retrofit2.Response
import retrofit2.http.GET
import java.lang.Exception


fun <T> handleResponse(response: Response<T>): T{
if (response.isSuccessful) return response.body()!!
else throw Exception()
}

interface ImageService {
@GET("meow")
suspend fun getRandomImage() : Response<CatImage>
}
49 changes: 35 additions & 14 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,50 @@ package otus.homework.coroutines

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import com.squareup.picasso.Picasso

class MainActivity : AppCompatActivity() {

lateinit var catsPresenter: CatsPresenter
lateinit var catsViewModel: CatsViewModel

private val diContainer = DiContainer()

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()
setContentView(layoutInflater.inflate(R.layout.activity_main, null))

val textView = findViewById<TextView>(R.id.fact_textView)
val imageView = findViewById<ImageView>(R.id.imageView)
findViewById<Button>(R.id.button).apply { this.setOnClickListener { catsViewModel.onButtonClicked() } }

catsViewModel = CatsViewModel(diContainer.service, diContainer.imageService)
catsViewModel.getCatInfo().observe(this){
when(it){
is Error ->{
textView.text = it.errorMsg
Picasso.get()
.load(R.drawable.ic_launcher_foreground)
.fit()
.centerInside()
.into(imageView)
}
is Success<*> ->{
if (it.data is CatsModel){
textView.text = it.data.fact.text
Picasso.get()
.load(it.data.image.fileUrl)
.fit()
.centerInside()
.into(imageView)
}

}
}
}
super.onStop()
}

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

import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlin.coroutines.CoroutineContext

class PresenterScope(): CoroutineScope {
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + CoroutineName("CatsCoroutine")
}
28 changes: 21 additions & 7 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,38 @@
android:layout_height="match_parent"
tools:context=".MainActivity">

<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginHorizontal="50dp"
android:layout_marginVertical="20dp"
android:maxHeight="200dp"
app:layout_constraintBottom_toTopOf="@+id/fact_textView"
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"
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:layout_marginBottom="30dp"
android:textColor="@color/black"
android:textSize="24sp"
app:layout_constraintBottom_toTopOf="@+id/button"
app:layout_constraintEnd_toEndOf="@+id/button"
app:layout_constraintStart_toStartOf="@+id/button" />

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

</otus.homework.coroutines.CatsView>
16 changes: 16 additions & 0 deletions app/src/main/res/layout/loading_view.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/loading"
android:textSize="24sp"
android:textColor="@color/black"
android:textAlignment="center"
android:layout_gravity="center"
android:gravity="center"/>

</LinearLayout>
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="no_server_response">Couldn\'t get response from a server.</string>
<string name="loading">Loading...</string>
</resources>